簡(jiǎn)單算法

實(shí)現(xiàn) trim

String.prototype.trim = function() {
    return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}

斐波那契數(shù)列

斐波那契數(shù)拳亿,通常用 F(n) 表示嚎朽,形成的序列稱(chēng)為斐波那契數(shù)列位他。該數(shù)列由 0 和 1 開(kāi)始吧黄,后面的每一項(xiàng)數(shù)字都是前面兩項(xiàng)數(shù)字的和部服。也就是:
F(0) = 0, F(1) = 1, F(N) = F(N - 1) + F(N - 2), 其中 N > 1,給定 N拗慨,計(jì)算 F(N)廓八。

function fib(N) {
    // 若 N <= 1,則返回 N
    if (N <= 1) {
        return N;
    }
    // 若 N == 2
    if (N == 2) {
        return 2;
    }
    // 至少需要三個(gè)變量存儲(chǔ) fib(N), fib(N-1) 和 fib(N-2)赵抢。
    let current = 0; // 代表 fib(N)
    let prev1 = 2; // 代表fib(N-1)
    let prev2 = 1; // 代表 fib(N-2)

    for (let i = 3; i <= N; i++) {
        current = prev1 + prev2;
        prev2 = prev1;
        prev1 = current;
    }
    return current;
}

時(shí)間復(fù)雜度:O(N)剧蹂。
空間復(fù)雜度:O(1),僅僅使用了 current烦却,prev1宠叼,prev2。

刪除字符串中的所有相鄰重復(fù)項(xiàng)

  • 輸入:"abbaca"
  • 輸出:"ca"
  • 解釋?zhuān)?/li>
  • 例如其爵,在 "abbaca" 中冒冬,我們可以刪除 "bb" 由于兩字母相鄰且相同,這是此時(shí)唯一可以執(zhí)行刪除操作的重復(fù)項(xiàng)醋闭。之后我們得到字符串 "aaca"窄驹,其中又只有 "aa" 可以執(zhí)行重復(fù)項(xiàng)刪除操作,所以最后的字符串為 "ca"证逻。
const removeDuplicates = function(s) {
    if (!s || s.length === 1) {
        return s || ''
    }
    const stock = []
    for (const item of s) {
        if (stock.length && item === stock[stock.length - 1]) {
            stock.pop()
        } else {
            stock.push(item)
        }
    }
    return stock.join('')
};
console.log(removeDuplicates('abbaca')) // ca

版本號(hào)排序

var versions = ["1.45.0", "1.5", "6", "3.3.3.3.3.3.3"];
// 要求從小到大排序乐埠,注意'1.45'比'1.5'大
function sortVersion(versions) {
// TODO
}
// => ['1.5','1.45.0','3.3.3.3.3.3','6']

const sortVersion = (list) => {
    if (!list || !list.length) {
        return
    }
    return list.sort((a, b) => {
        let aArr = a.split('.')
        let bArr = b.split('.')
        let maxLen = aArr >= bArr ? aArr : bArr
        for (let i = 0; i < maxLen; i++) {
            let x = aArr[i] || 0
            let y = bArr[i] || 0
            if (x - y !== 0) {
                return x - y
            }
        }
    })
}

打亂數(shù)組

打亂一個(gè)沒(méi)有重復(fù)元素的數(shù)組
洗牌算法:從最后一個(gè)元素開(kāi)始,從數(shù)組中隨機(jī)選出一個(gè)位置囚企,交換丈咐,直到第一個(gè)元素。

class Disorder {
    constructor(arr) {
        this.originArr = [ ...arr ]
    }

    reset() {
        return this.originArr
    }

    shuffle() {
        const shuffleArr = [ ...this.originArr ]
        let curLen = shuffleArr.length - 1
        while (curLen > -1) {
            // 生成一個(gè)范圍在當(dāng)前下標(biāo)到數(shù)組末尾元素下標(biāo)之間的隨機(jī)整數(shù)
            const random = Math.floor(shuffleArr.length * Math.random())
            console.log(random);
            // 將當(dāng)前元素和隨機(jī)選出的下標(biāo)所指的元素互相交換
            [ shuffleArr[curLen], shuffleArr[random] ] = [ shuffleArr[random], shuffleArr[curLen] ]
            curLen--
        }
        return shuffleArr
    }
}

var obj = new Disorder([ 1, 4, 8, 9 ])
console.log(obj.shuffle());
console.log(obj.reset());

二叉樹(shù)的最大深度

給定一個(gè)二叉樹(shù)龙宏,找出其最大深度棵逊。二叉樹(shù)的深度為根節(jié)點(diǎn)到最遠(yuǎn)葉子節(jié)點(diǎn)的最長(zhǎng)路徑上的節(jié)點(diǎn)數(shù)。

function TreeDepth(pRoot) {
    if (!pRoot) {
        return 0;
    }
    let left = TreeDepth(pRoot.left);
    let right = TreeDepth(pRoot.right);
    return Math.max(left, right) + 1;
}

二叉樹(shù)的鏡像

操作給定的二叉樹(shù)银酗,將其變換為源二叉樹(shù)的鏡像辆影。

function Mirror(pRoot) {
    if (!pRoot) {
        return null
    }
    let temp = pRoot.left
    pRoot.left = pRoot.right
    pRoot.left = temp

    Mirror(pRoot.left)
    Mirror(pRoot.right)

    return pRoot
}

樹(shù)的子結(jié)構(gòu)

輸入兩棵二叉樹(shù)A,B黍特,判斷B是不是A的子結(jié)構(gòu)蛙讥。(ps:我們約定空樹(shù)不是任意一個(gè)樹(shù)的子結(jié)構(gòu))

// 比較兩棵樹(shù)是否相同
function compTree(root1, root2) {
    if (!root2) {
        return true
    }
    if (!root1) {
        return false
    }
    if (root1.val !== root2.val) {
        return false
    }
    return compTree(root1.left, root2.left) && compTree(root1.right, root2.right)
}

// 判斷是否子結(jié)構(gòu)
function HasSubtree(pRoot1, pRoot2) {
    if (!pRoot1 || !pRoot2) {
        return false
    }
    if (!compTree(pRoot1, pRoot2)) {
        return HasSubtree(pRoot1.left, pRoot2) || HasSubtree(pRoot1.right, pRoot2)
    }
    return true
}

給一個(gè)嵌套對(duì)象,返回展平對(duì)象(屬性為 a.b.c)

const obj = {
    a: 'a',
    b: [1, 2],
    c: true,
    d: function() { console.log('d') },
    e:  {
        a: 'a-e',
        b: [1, 2, 3],
        c: false,
        d: function() { console.log('e-d') },
        f:  {
            a: 'a-f',
            b: [1, 2, 4],
            c: true,
            d: function() { console.log('f-d') },
        }
    }
}

function flatObj (data) {
    if (!data || data.constructor !== Object) {
        return {}
    }
    const obj = {}
    function flat(data, baseKey) {
        // for...in 會(huì)遍歷原型鏈上所有屬性灭衷,不推薦使用
        Object.keys(data).forEach(key => {
            const value = data[key];
            const finalKey = baseKey ? `${baseKey}.${key}` : key;
            if (value.constructor === Object) {
                flat(value, finalKey);
            } else {
                obj[finalKey] = value;
            }
        })
        return obj
    }
    return flat(data);
}

const data = flatObj(obj)
data.d()
data['e.d']()
data['e.f.d']()

計(jì)算一個(gè)有序數(shù)組中次慢,某個(gè)數(shù)字出現(xiàn)的次數(shù)

  1. 方法1:用兩個(gè)循環(huán),一個(gè)從頭找一個(gè)從尾找,找到第一次出現(xiàn)的位置和最后一次出現(xiàn)的位置迫像。再相減即可劈愚。
function GetNumberOfK(data, k) {
    var start = -1
    var end = -1
    for (var i = 0; i < data.length; i++) {
        if (data[i] == k) {
            start = i;
            break
        }
    }
    for (var j = data.length - 1; j > -1; j--) {
        if (data[j] == k) {
            end = j
            break
        }
    }
    if (start != -1 && end != -1) {
        return end - start + 1;
    } else {
        return 0
    }
}
  1. 方法2:
    二分法,找到數(shù)字出現(xiàn)的第一次和最后一次闻妓。

function GetNumberOfK(data, k) {
    if (data.length == 0) {
        return 0;
    }
    var first = theFirst(data, 0, data.length - 1, k)
    var last = theLast(data, first - 1, data.length - 1, k)
    if (first != -1 && last != -1) {
        return last - first + 1;
    } else {
        return 0;
    }
}
// 找到第一次出現(xiàn)K的位置
function theFirst(data, start, end, k) {
    if (start > end) {
        return -1;
    }
    var mid = parseInt((start + end) / 2)
    if (data[mid] > k) {
        end = mid - 1;
        return theFirst(data, start, end, k)
    } else if (data[mid] < k) {
        start = mid + 1
        return theFirst(data, start, end, k)
    }
    // 還要多加一個(gè)判斷如果mid-1也為k的話菌羽,說(shuō)明第一次出現(xiàn)的位置還更小。
    else if ((mid - 1 >= 0) && (data[mid - 1] == k)) {
        return theFirst(data, start, mid - 1, k)
    } else {
        return mid;
    }
}
// 找到最后一次出現(xiàn)K的位置
function theLast(data, start, end, k) {
    if (start > end) {
        return -1;
    }
    var mid = parseInt((start + end) / 2)
    if (data[mid] > k) {
        end = mid - 1;
        return theLast(data, start, end, k)
    } else if (data[mid] < k) {
        start = mid + 1
        return theLast(data, start, end, k)
    }
    // 還要多加一個(gè)判斷如果mid+1也為k的話纷闺,說(shuō)明最后一次出現(xiàn)的位置還更大算凿。
    else if ((mid + 1 < data.length) && (data[mid + 1] == k)) {
        return theLast(data, mid + 1, end, k)
    } else {
        return mid;
    }
}

傳入真實(shí) dom份蝴,輸出 json

const handleNode = (node) => {
    if (!node) {
        return
    }
    return {
        name: node.nodeName,
        nodes: node.children && node.children.length ?
            Array.from(node.children).map(item => handleNode(item)) :
            node.innerHTML
    }
}
console.log(handleNode(document.body));

一個(gè)數(shù)組犁功,獲取出現(xiàn)次數(shù)最多的元素及其次數(shù)

const calcMaxNum = arr => {
    if (!Array.isArray(arr) || !arr.length) {
        return
    }
    const map = new Map()
    let maxItem = null
    let maxNum = 0
    arr.forEach(item => {
        if (map.has(item)) {
            map.set(item, map.get(item) + 1)
        } else {
            map.set(item, 1)
        }
        if (map.get(item) > maxNum) {
            maxItem = item
            maxNum = map.get(item)
        }
    })
    return { maxItem, maxNum }
}
calcMaxNum([1, 2, 3, 1, '2', '3', '1', 3, 5, 4, 3])

輸入 [ [1, 4, 7], [2, 5, 8], [3, 6, 9]],輸出 [ [1, 2, 3], [4, 5, 6], [7, 8, 9]]

方式一:
const fn = (arr) => {
    if (!Array.isArray(arr) || !arr.length) {
        return;
    }
    return Array(arr[0].length).fill('').map((item, index) => arr.map(arrItem => arrItem[index]))
}

// 方式二:
function fn(arr) {
    const newArr = [];
    for (let i = 0; i < arr[0].length; i++) {
        newArr.push([]);
    }

    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr[0].length; j++) {
            newArr[i][j] = arr[j][i]
        }
    }
    return newArr;
}
fn([[1, 4, 7], [2, 5, 8], [3, 6, 9]])

N[string]婚夫,表示 string 正好重復(fù) N 次

const decodeStr = function (str) {
    if (typeof str !== "string") {
        throw "請(qǐng)輸入字符串";
    }
    let index = 0;
    let decodeQueue = [];
    while (index < str.length) {
        let eleStr = str[index];
        if (eleStr === "[") {
            decodeQueue.push(index);
        }
        if (decodeQueue.length > 0 && eleStr === "]") {
            let leftIndex = decodeQueue.pop();
            let rightIndex = index;
            str = strFormat(str, leftIndex, rightIndex);
            index = 0;
            continue;
        }
        index++;
    }
    return str;
};
const strFormat = function (str, startIndex, rightIndex) {
    // 輔助函數(shù): 將形如str[]對(duì)應(yīng)左右index展開(kāi);
    let temp = str.substring(startIndex + 1, rightIndex);
    let copiedStr = "";
    let copyNum = "";
    while (str[--startIndex] >= 0) {
        copyNum = str[startIndex] + copyNum;
    }
    for (let i = 0; i < copyNum; i++) {
        copiedStr += temp;
    }
    str =
        str.substring(0, startIndex + 1) +
        copiedStr +
        str.substring(rightIndex + 1);
    return str;
};
decodeStr('3[abc]2[cd]ff') // 'abcabcabccdcdff'

判斷b是否為a的子序列

const isSubsequence = (b, a) => {
    let bi = 0;
    let ai = 0;
    while (bi < b.length) {
        if (a[ai] === b[bi]){
            bi++;
        }
        ai++;
        if (ai > a.length) {
            return false;
        }
    }
    return true;
};
isSubsequence([1, 5, 11], [1, 3, 5, 7, 11]); // true

請(qǐng)完成下列函數(shù)

  • 可以批量請(qǐng)求數(shù)據(jù)浸卦,所有的 URL 地址在 urls 參數(shù)中
  • 同時(shí)可以通過(guò) max 參數(shù)控制請(qǐng)求的并發(fā)度
  • 當(dāng)所有請(qǐng)求結(jié)束之后,需要執(zhí)行 callback 回調(diào)函數(shù)案糙。
  • 發(fā)請(qǐng)求的函數(shù)可以直接使用 fetch 即可
/**
 *
 * @param { Array } urls  請(qǐng)求地址數(shù)組
 * @param { Number } max 最大并發(fā)請(qǐng)求數(shù)
 * @param { Function } callback  回調(diào)地址
 */
function parallelFetch(urls, max, callback) {
    // 如果當(dāng)前環(huán)境不支持 fetch , 則提示程序無(wú)法正常運(yùn)行
    if (!window.fetch || "function" !== typeof window.fetch) {
        throw Error("當(dāng)前環(huán)境不支持 fetch 請(qǐng)求限嫌,程序終止")
    }
  
    // 如果參數(shù)有誤,則提示輸入正確的參數(shù)
    if (!urls || urls.length <= 0) {
        throw Error("urls is empty: 請(qǐng)傳入正確的請(qǐng)求地址")
    }
  
    const _urlsLength = urls.length; // 請(qǐng)求地址數(shù)組的長(zhǎng)度
    const _max = max || 1 // 保證最大并發(fā)值的有效性
    let _currentIndex = 0 // 當(dāng)前請(qǐng)求地址的索引
    let _maxFetch = max <= _urlsLength ? max : _urlsLength // 當(dāng)前可以正常請(qǐng)求的數(shù)量时捌,保證最大并發(fā)數(shù)的安全性
    let _finishedFetch = 0 // 當(dāng)前完成請(qǐng)求的數(shù)量怒医,用于判斷何時(shí)調(diào)用回調(diào)
  
    console.log(`開(kāi)始并發(fā)請(qǐng)求,接口總數(shù)為 ${_urlsLength} 奢讨,最大并發(fā)數(shù)為 ${_maxFetch}`)
    // 根據(jù)最大并發(fā)數(shù)進(jìn)行循環(huán)發(fā)送稚叹,之后通過(guò)狀態(tài)做遞歸請(qǐng)求
    for (let i = 0; i < _maxFetch; i++) {
        fetchFunc()
    }

    // 請(qǐng)求方法
    function fetchFunc() {
        // 如果所有請(qǐng)求數(shù)都完成,則執(zhí)行回調(diào)方法
        if (_finishedFetch === _urlsLength) {
            console.log(`當(dāng)前一共 ${_urlsLength} 個(gè)請(qǐng)求拿诸,已完成 ${_finishedFetch} 個(gè)`)
            if ("function" === typeof callback) {
                return callback()
            }
            return false
        }
        // 如果當(dāng)前請(qǐng)求的索引大于等于請(qǐng)求地址數(shù)組的長(zhǎng)度扒袖,則不繼續(xù)請(qǐng)求
        if (_currentIndex >= _urlsLength) {
            _maxFetch = 0
        }
  
        // 如果可請(qǐng)求的數(shù)量大于0,表示可以繼續(xù)發(fā)起請(qǐng)求
        if (_maxFetch > 0) {
            console.log( `當(dāng)前正發(fā)起第 ${_currentIndex + 1 } 次請(qǐng)求亩码,當(dāng)前一共 ${_urlsLength} 個(gè)請(qǐng)求季率,已完成 ${_finishedFetch} 個(gè),請(qǐng)求地址為:${urls[_currentIndex]}`)
            // 發(fā)起 fetch 請(qǐng)求
            fetch(urls[_currentIndex])
                .then((res) => {
                    // TODO 業(yè)務(wù)邏輯描沟,正常的邏輯飒泻,異常的邏輯
                    // 當(dāng)前請(qǐng)求結(jié)束,正常請(qǐng)求的數(shù)量 +1
                    _maxFetch += 1
                    _finishedFetch += 1
                    fetchFunc()
                })
                .catch((err) => {
                    // TODO 異常處理吏廉,處理異常邏輯
                    // 當(dāng)前請(qǐng)求結(jié)束泞遗,正常請(qǐng)求的數(shù)量 +1
                    _maxFetch += 1
                    _finishedFetch += 1
                    fetchFunc()
                });
            // 每次請(qǐng)求,當(dāng)前請(qǐng)求地址的索引  +1
            _currentIndex += 1
            // 每次請(qǐng)求迟蜜,可以正常請(qǐng)求的數(shù)量 -1
            _maxFetch -= 1
        }
    }
}
  
let urls = []
for (let i = 0; i < 100; i++) {
    urls.push(`https://jsonplaceholder.typicode.com/todos/${i}`)
}
const max = 10
const callback = () => {
    console.log("我請(qǐng)求完了")
}
parallelFetch(urls, max, callback)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刹孔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌髓霞,老刑警劉巖卦睹,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異方库,居然都是意外死亡结序,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)纵潦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)徐鹤,“玉大人,你說(shuō)我怎么就攤上這事邀层》稻矗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵寥院,是天一觀的道長(zhǎng)劲赠。 經(jīng)常有香客問(wèn)我,道長(zhǎng)秸谢,這世上最難降的妖魔是什么凛澎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮估蹄,結(jié)果婚禮上塑煎,老公的妹妹穿的比我還像新娘。我一直安慰自己臭蚁,他們只是感情好最铁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著刊棕,像睡著了一般炭晒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上甥角,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天网严,我揣著相機(jī)與錄音,去河邊找鬼嗤无。 笑死震束,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的当犯。 我是一名探鬼主播垢村,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼嚎卫!你這毒婦竟也來(lái)了嘉栓?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侵佃,沒(méi)想到半個(gè)月后麻昼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馋辈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年抚芦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迈螟。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叉抡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出答毫,到底是詐尸還是另有隱情褥民,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布烙常,位于F島的核電站轴捎,受9級(jí)特大地震影響鹤盒,放射性物質(zhì)發(fā)生泄漏蚕脏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一侦锯、第九天 我趴在偏房一處隱蔽的房頂上張望驼鞭。 院中可真熱鬧,春花似錦尺碰、人聲如沸挣棕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)洛心。三九已至,卻和暖如春题篷,著一層夾襖步出監(jiān)牢的瞬間词身,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工番枚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留法严,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓葫笼,卻偏偏與公主長(zhǎng)得像深啤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子路星,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容