1. 程式人生 > >前端面試常見演算法題總結

前端面試常見演算法題總結

### 判斷一個單詞是否是迴文 ###
思路:將字串轉換為陣列,利用陣列方法reverse()比較翻轉後的字串是否與源字串一致。

實現:

    function checkPalindrome(str) {
        return str == str.split('').reverse().join('');
    }
### 去掉一組整型陣列重複的值 ###

    function uniqueArr(arr) {
        var result = [];
        for(var i = 0; i < arr.length; i++) {
            if(arr.indexOf(arr[i]) === i) {

                result.push(arr[i]);
            }
        }
        return result;
    }
    uniqueArr([1,13,24,11,11,14,1,2]);//返回 [1, 13, 24, 11, 14, 2]
### 統計一個字串出現最多的字母 ###
    function maxDuplicateLetter(str) {
        //如果字串僅有一個字元,即為該字元
        if(str.length === 1) {
            return str;
        }
        var letterObj = {};

        for(var i = 0; i < str.length; i++) {
            if(!letterObj[str[i]]) {//存放字母的物件中還未記錄過該字母出現的次數
                letterObj[str[i]] = 1;
            }
            letterObj[str[i]] += 1;
        }
        //接下來尋找存放字母的物件中最大的value所對應的key
        var maxValue = 1;
        var maxKey = '';
        for(var key in letterObj) {

            if(letterObj[key] > maxValue) {
                maxValue = letterObj[key];
                maxKey = key;
            }
        }
        return maxKey;
    }
    maxDuplicateLetter("abcdddbb");//返回 "a"
### 排序演算法 ###
**(1)氣泡排序** 
依次比較相鄰兩個數的大小,進行位置上的交換,若按由小到大排序,第一輪可以將最大的排在最右邊。
平均時間複雜度:O(n^2)  &nbsp;&nbsp;最好情況:O(n) &nbsp;&nbsp;  最壞情況:O(n^2)
空間複雜度:O(1)
排序方式:In-place
穩定性:穩定

    function bubbleSort(arr) {
        for(var i = 0; i < arr.length; i++) {
            for(var j = 0; j < arr.length - i -1; j ++) {
                // 由小到大排序
                if(arr[j] > arr[j + 1]){
                    var swap = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = swap;
                }
            }
        }
        return arr;
    }
    bubbleSort([3, 2, 4, 1, 7]);//返回 [1, 2, 3, 4, 7]
**(2)快速排序**
參考某個元素值,將小於它的值,放到左陣列中,大於它的值的元素就放到右陣列中,然後遞迴進行上一次左右陣列的操作,返回合併的陣列就是已經排好順序的陣列。
平均時間複雜度: O(n log n)  &nbsp;&nbsp;最好情況:O(n log n) &nbsp;&nbsp;  最壞情況:O(n^2)
空間複雜度:O(1)
排序方式:In-place
穩定性:不穩定

    function quickSort(arr) {
        if(arr.length <= 1) {
            return arr;
        }
        var referValue = arr[0];
        var leftArr = [];
        var rightArr = [];
        // 由小到大排序
        for(var i = 1; i < arr.length; i++) {
            if(arr[i] < referValue) {
                leftArr.push(arr[i]);
            } else {
                rightArr.push(arr[i]);
            }
        }
        return quickSort(leftArr).concat([referValue], quickSort(rightArr));
    }
    quickSort([3, 2, 4, 1, 7]);//返回 [1, 2, 3, 4, 7]
另外還有 **選擇排序、插入排序、希爾排序、歸併排序、堆排序、計數排序、桶排序等**,見部落格[js十大排序演算法](https://www.cnblogs.com/beli/p/6297741.html)
### 不借助臨時變數,進行兩個整數的交換 ###
利用 + – 去進行運算,類似 a = a + ( b – a) 實際上等同於最後 的 a = b;

    function swap([a, b]) {
        var b = b - a;
        var a = a + b;
        var b = a - b;
        return [a, b];
    }
    swap([2, 5]);//返回 [5, 2]
### 使用canvas 繪製一個有限度的斐波那契數列的曲線 ###
![斐波那契數列曲線](http://img1.vued.vanthink.cn/vued90edf7b944ec479ee8b4203cf56e158d.png)
數列長度限定在9時的影象。
斐波那契數列,又稱黃金分割數列,指的是這樣一個數列:0、1、1、2、3、5、8、13、21、34、……     
`fibo[i] = fibo[i-1]+fibo[i-2];`
即生成斐波那契數列,然後再將該數列值作為半徑,利用canvas arc方法繪製曲線。

    function generateFibo(n) {
        var fiboArr = [];
        var i = 0;
        while(i < n) {
            if (i <= 1) {
                fiboArr.push(i);
            } else {
                fiboArr[i] = fiboArr[i - 1] + fiboArr[i - 2];
            }
            i++;
        }
        return fiboArr;
    }
    generateFibo(6);//返回 [0, 1, 1, 2, 3, 5]
### 找出正陣列的最大差值 ###
相當於找到一個數組中的最大值與最小值,最大差值即為兩者之差。

    function maxDifference(arr) {
        var minValue = arr[0];
        var maxDiffer = 0;
        for(var i = 0; i < arr.length; i++) {
            minValue = Math.min(minValue, arr[i]);
            currentDiffer = arr[i] - minValue;
            maxDiffer = Math.max(maxDiffer, currentDiffer);
        }
        return maxDiffer;
    }
    maxDifference([10,5,11,7,8,9]);//返回 6
### 隨機生成指定長度的字串 ###
    function randomString(n) {
        var rangeStr = 'abcdefghijklmnopqrstuvwxyz0123456789';
        var l = rangeStr.length;
        var randomStr = '';
        for(var i = 0; i < n; i++) {
            randomStr += rangeStr.charAt(Math.floor(Math.random() * l));
        }
        return randomStr;
    }
    randomString(10);//返回 "itfjah8rte"
### 實現類似getElementsByClassName 的功能 ###
查詢某個DOM節點下面的包含某個class的所有DOM節點?不允許使用原生提供的 getElementsByClassName、 querySelectorAll 等原生提供DOM查詢的函式。

    function queryClassName(node, name) {
        var starts = '(^|[ \n\r\t\f])',
            ends = '([ \n\r\t\f]|$)';
        var resultArr = [],
            reg = new RegExp(starts + name + ends),
            elements = node.getElementsByTagName("*");
            length = elements.length,
            i = 0;
        while(i < length) {
            var element = elements[i];
            if(reg.test(element.className)) {
                resultArr.push(element);
            }
            i++;
        }
        return resultArr;
    }
    // 方法2
    function queryClassName2(node, name) {
        var elements = node.getElementsByTagName("*"),
            length = elements.length,
            resultArr = [];
        for(var i = 0; i < length; i ++) {
            if(elements[i].className) {
                var classNames = elements[i].className.split(" ");/*這裡其實還要考慮類名間隔大於一個空格的情況*/
                if(classNames.indexOf(name) !== -1) {
                    resultArr.push(elements[i]);
                }
            }
        }
        return resultArr;
    }
    //HTML結構
    <ul id="ull">  
        <li>0</li>  
        <li class='box box2'>1</li>  
        <li>2</li>  
        <li class='box1'>3</li>  
        <li class='box1'>4</li>  
        <li class='box box1'>5</li>   
    </ul>
    //測試結果
     window.onload = function() {
        node = document.getElementById("ull");
        queryClassName(node, "box");//返回 (2) [li.box.box2, li.box.box1]
        queryClassName2(node, "box");// 返回 (2) [li.box.box2, li.box.box1]
    };
### JS 實現二叉查詢樹(Binary Search Tree) ###
在實際使用時會根據連結串列和有序陣列等資料結構的不同優勢進行選擇。有序陣列的優勢在於二分查詢,連結串列的優勢在於資料項的插入和資料項的刪除。但是在有序陣列中插入資料就會很慢,同樣在連結串列中查詢資料項效率就很低。綜合以上情況,二叉樹可以利用連結串列和有序陣列的優勢,同時可以合併有序陣列和連結串列的優勢,二叉樹也是一種常用的資料結構。
二叉查詢樹,也稱二叉搜尋樹、有序二叉樹(英語:ordered binary tree)是指一棵空樹或者具有下列性質的二叉樹:

    任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
    任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
    任意節點的左、右子樹也分別為二叉查詢樹;
    沒有鍵值相等的節點。二叉查詢樹相比於其他資料結構的優勢在於查詢、插入的時間複雜度較低。為O(log n)。二叉查詢樹是基礎性資料結構,用於構建更為抽象的資料結構,如集合、multiset、關聯陣列等。
**二叉樹相關概念:**
凡是每個節點都最多有兩個叉的樹,都叫二叉樹。
查詢樹和排序樹是一個東西。特點是中序遍歷一遍的結果是單調的。這種樹建出來可以用來做二分搜尋。
平衡樹一般是排序樹的一種,並且加點條件,就是任意一個節點的兩個叉的深度差不多(比如差值的絕對值小於某個常數,或者一個不能比另一個深出去一倍之類的)。
這樣的樹可以保證二分搜尋任意元素都是O(log n)的,一般還附帶帶有插入或者刪除某個元素也是O(log n)的的性質。
二叉樹由節點(node)和邊組成。節點分為根節點、父節點、子節點。如下圖所示:

![二叉樹示意圖](https://img-blog.csdn.net/20160919221509693)
紅色是根節點(root)。藍色是子節點也是父節點,綠色的是子節點。其餘的線是邊。節點和連結串列中的節點一樣都可以存放資料資訊。樹中的邊可以用自引用表示,這種引用就是C/C++裡面的指標。通常來說樹是頂部小,底部大,且樹呈分層結構。root節點時第0層,以此類推。二叉樹最多有兩個節點。
二叉樹搜尋: 二叉樹一個節點左子節點的關鍵字小於這個節點,右子節點關鍵字大於或等於這個父節點。
建立一個樹節點。
**BST建立過程:**
(1)建立一個樹節點包括左節點引用和右節點引用。
(2)建立一個樹結構。 建立一個樹結構首先是向一個樹種插入資料節點。當一棵樹為null時,資料項是從樹的root節點處開始插入,之後的插入順序是根據搜尋節點順序規則進行插入。具體規則是:如果資料項比父節點的資料項要小,則插在父節點的左節點(leftNode),如果比父節點的資料項要大,則將新的node插入在父節點的右節點處(rightNode)。
插入資料節點過程如下所示:
![BST插入資料節點示意圖](https://img-blog.csdn.net/20160919230148150)
插入節點的過程中其實也就是對tree遍歷的過程,最終根據條件遍歷到左右節點為null時進行新增新的節點。
**查詢關鍵字**
查詢關鍵字是資料結構一項重要操作項,在有序陣列中通過二分排序效率非常高。在二叉樹中的查詢效率也比較高。因為二叉樹的新增node的過程就是根據資料項的大小進行有序新增的,並不是毫無秩序的插入資料項。在有序的基礎上進行查詢關鍵字效率就會快很多。
樹的最值查詢在樹中查詢是比較容易的,因為從root開始查詢,最小值只會出現所有父節點的左節點處,同樣最大值只會出現在所有父節點的沿著右節點搜尋的最底層右節點處。
[參考自部落格](http://blog.csdn.net/cai2016/article/details/52589952)
**刪除節點**
給出如下二叉查詢樹

![二叉查詢樹](http://ou3oh86t1.bkt.clouddn.com/blog/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98/BST.png)
刪除節點3之後,可以返回

![新的BST1](http://ou3oh86t1.bkt.clouddn.com/blog/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98/newBST1.png)
或者

![新的BST2](http://ou3oh86t1.bkt.clouddn.com/blog/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98/newBST2.png)
思路:
若要刪除一個BST的一個結點,需要考慮如下三種情況:

    需要刪除的節點下並沒有其他子節點
    需要刪除的節點下有一個子節點(左或右)
    需要刪除的節點下有兩個子節點(既左右節點都存在)
對這三種情況分別採取的措施是:
    直接刪除此結點
    刪除此結點,將此結點父節點連線到此結點左(右)子樹
    找出此結點右子樹中的最小結點,用以代替要刪除的結點,然後刪除此最小結點

**設定每個節點的資料結構:**

    class Node {
        constructor(data, left, right) {
            this.data = data;
            this.left = left;
            this.right = right;
        }
    }
樹由節點構成,由根節點逐漸延生到各個子節點,因此它基本的結構就是具備一個根節點,具備新增,查詢和刪除節點的方法。

    // 構建BST,具備一個根節點、以及新增、查詢、刪除節點的方法
    class BinarySearchTree {
        constructor() {
            this.root = null;
        }
        // 插入節點的方法
        insert(data) {
            let n = new Node(data, null, null);
            if (!this.root) { //如果此二叉樹為空,則資料項從樹的root節點處開始插入
                return this.root = n;
            }
            let currentNode = this.root;
            let parent = null;
            while (true) {
                parent = currentNode; //儲存當current變為null之前的那一個父節點
                if (data < currentNode.data) { //插在父節點的左節點
                    currentNode = currentNode.left;
                    if (currentNode === null) { //不斷向左node尋找是否為null
                        parent.left = n;
                        break;
                    }
                } else { //插在父節點的右節點
                    currentNode = currentNode.right;
                    if (currentNode === null) {
                        parent.right = n;
                        break;
                    }
                }
            }
        }
        // 刪除資料項
        remove(data) {
            this.root = this.removeNode(this.root, data);
        }
        // 刪除節點
        // 刪除樹中與給定值相同的節點,如果樹中沒有相同值的節點,則不做處理,應該保證處理之後的樹仍是二叉查詢樹。
        removeNode(node, data) {
            if (node === null) { // 如果根節點為空
                return null;
            }
            if (data === node.data) {
                // 沒有子節點,即node為葉子節點
                if (node.left === null && node.right === null) {
                    return null;
                }
                // 要刪除的節點下只有右節點
                if (node.left === null) {
                    return node.right;
                }
                // 要刪除的節點下只有左節點
                if (node.right === null) {
                    return node.left;
                }
                // 要刪除的節點下有兩個子節點的情況
                // getSmallest用於找到該節點右子樹中的最小節點,用以替代要刪除的節點,然後刪除此最小節點
                let getSmallest = function (node) {
                    if (node.left === null && node.right === null) {
                        return node;
                    }
                    if (node.left !== null) {
                        return node.left;
                    }
                    if (node.right !== null) {
                        return getSmallest(node.right);
                    }
                }
                let temNode = getSmallest(node.right);
                node.data = temNode.data;
                node.right = this.removeNode(temNode.right, temNode.data);
                return node;
            } else if (data < node.data) {
                node.left = this.removeNode(node.left, data);
                return node;
            } else {
                node.right = this.removeNode(node.right, data);
                return node;
            }
        }
        // 查詢方法
        find(data) {
            let currentNode = this.root;
            while (currentNode !== null) {
                if (data === currentNode.data) {
                    return true;
                }
                if (data < currentNode.data) {
                    if (currentNode.left !== null) {
                        currentNode = currentNode.left;
                    } else {
                        return false;
                    }
                } else {// data > currentNode.data
                    if (currentNode.right !== null) {
                        currentNode = currentNode.right;
                    } else {
                        return false;
                    }
                }
            }
        }
    }

有關陣列的一些操作見部落格後半部分[前端面試中的常見的演算法問題](https://www.cnblogs.com/libin-1/p/5998870.html)

下面是一篇總結常見資料結構的javascript實現的文章:
**[常見資料結構的javascript實現](http://blog.csdn.net/haoshidai/article/details/52263191)**

相關推薦

前端面試常見演算法總結

### 判斷一個單詞是否是迴文 ###思路:將字串轉換為陣列,利用陣列方法reverse()比較翻轉後的字串是否與源字串一致。實現:    function checkPalindrome(str) {        return str == str.split('').r

JS面試常見演算法

學習資料結構與演算法對於工程師去理解和分析問題都是有幫助的。如果將來當我們面對較為複雜的問題,這些基礎知識的積累可以幫助我們更好的優化解決思路。下面羅列在前端面試中經常撞見的幾個問題吧。 1.統計一個字串出現最多的字母和出現的次數 第一種方法: var s

面試常見演算法---氣泡排序python

兩個迴圈判斷相鄰陣列是否交換class Solution(): def Bubble_sort(self, list): for i in range(len(list)-1, 0, -1): for j in range(i)

前端面試演算法

雖說我們很多時候前端很少有機會接觸到演算法。大多都互動性的操作,然而從各大公司面試來看,演算法依舊是考察的一方面。實際上學習資料結構與演算法對於工程師去理解和分析問題都是有幫助的。如果將來當我們面對較為複雜的問題,這些基礎知識的積累可以幫助我們更好的優化解決思路

面試演算法總結

1.使用遞迴方法求陣列和 當時聽到這個問題一臉懵逼,因為我們平時求陣列和都是直接迴圈去計算的,突然要求用遞迴算,表示當時一點思路也沒有,也可能還是因為對遞迴演算法不太熟吧,總之當時著實尷尬,後來想想,

PHP面試常見演算法、函式總結

<?php //a=10,b=15 在不用第三個變數的前提下交換a b的值 //使用list(): $a = "fsdfds"; $b = "xiaorui"; list($a,$b) = array($b,$a); echo $a."-".$b; /

面試常考演算法總結(二)

題目連結:試卷1和試卷2。 題目1:對於一個無序陣列A,請設計一個演算法,求出需要排序的最短子陣列的長度。給定一個整數陣列A及它的大小n,請返回最短子陣列的長度。 測試樣例: [1,5,3,4,2,6,7],7 返回:4 分析:1.先判斷依次最小值是否在正確位置,直到

面試常見演算法總結

這裡是我在網上搜索的一些面試常見演算法,總結一下,利人利己。 top k 問題: 選取第k大(前k大)的數可以採用類似於快速排序的方法, 利用快速排序的思想,從陣列S中隨機找出一個元素X,把陣列分為兩部分Sa和Sb。Sa中的元素大於等於X,Sb中元素小於X。

前端面試算法

result 最大 ntp sans ica title RR size pri 1. //數組去重的方法let arr = [1,2,5,3,4,2,9,6,4,4];let unique = function(arr){ let hashTable = {};

常見演算法

1.用簡單素數篩選法求N以內的素數。 void printPrime() { int n; scanf("%d",&n); int i,j; for(i=2;i<=n;i++) //遍歷2~N的所有數 { for(j=2;j<=i;j++) {

前端面試常見問題(2018.10.18)

1. position的定位方式?檢視 常見的有4種: position:static(靜態定位) 靜態定位;是position的預設值,元素框正常生成,也就是沒有定位時的正常顯示。 position:relative(相對定位) 生成的位置相對於自身定位的,

2018年秋招面試常見資料庫知識總結

MYAQL: 事務:事務是併發控制的基本單元,事務是一個操作序列,要麼都執行,要麼都不執行, 他是一個不可分割的工作單位,事務是維護資料庫一致性的單位。 四個ACID基本性質: 1.原子性:要麼都執行,要麼都不執行。 2.一致性:合法的資料才可以被寫入。 3.

面試經典演算法集錦——《劍指 offer》小結

從今年 3 月份開始準備找實習,到現在校招結束,申請的工作均為機器學習/資料探勘演算法相關職位,也拿到了幾個 sp offer。經歷這半年的洗禮,自己的綜合能力和素質都得到了一個質的提升。 實話說對於未來去哪裡,即將如何發展還沒有清晰的規劃。迷茫總是會有的,但這並不是停止腳步的理由。找工作是在漫

LeetCode面試常見100( TOP 100 Liked Questions)

這篇文章是關於LeetCode Top 100 Liked Questions 的 專欄記錄,其中部分題目可能包括解題思路和多種優化解法。我把自己的思路都記錄在這裡,如果你看見了,請記得點個贊吧,蟹蟹【手動笑臉】。 目錄: 1、Two Su

面試精選邏輯推理總結

類似的殺人遊戲 1、500張骨牌整齊地排成一行,按順序編號為1、2、3、……、499、500。第一次拿走所有奇數位置上的骨牌,第二次再從剩餘骨牌中拿走奇數位置上的骨牌,以此類推。請問最後剩下的一張骨牌的編號是?(256)【2014阿里筆試題】 思路解析:

【2019春招準備:常見演算法1-10】

【內容】 topK 臺階 非遞迴遍歷二叉樹 【補充】 ================== 1.topK 2.青蛙跳臺階 【@深信服 大資料開發】 【題目描述 】 一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。

經典演算法:大資料處理常見演算法

第一部分、十道海量資料處理 1、海量日誌資料,提取出某日訪問百度次數最多的那個IP。   此題,在我之前的一篇文章演算法裡頭有所提到,當時給出的方案是:IP的數目還是有限的,最多2^32個,所以可以考慮使用hash將ip直接存入記憶體,然後進行統計。  再詳細介紹下此方案:

Web前端面試常見問題

記住: 很多問題都是開放的,可以引發有趣的討論。這比直接的答案更能體現此人的能力。 常見問題: ● Q: 你在昨天/本週學到了什麼? ● Q: 編寫程式碼的哪些方面能夠使你興奮或感興趣? ● Q: 在製作一個Web應用或Web站點的過程中,你是如何考

WEB前端面試常見的問題及答案

一.html+css:在w3c的標準模式下,width=width,但是在怪異模式下,width=border*2+padding*2+width;其中後代元素的width:100%;二.html5新特

面試常見邏輯小整理

題一、 1 1 1 2 1 1 2 1 1 1 1 1 2 2 1 下一行是什麼? 答案: 312211 題二、 (1)燒一根不均勻的繩要用一個小時,如何用它來判斷半個小時? (2)燒一根不均勻的繩,從頭燒到尾總共需要1個小時。現在有若干條材質相同的繩子,問如何用燒