求最长递增子序列!

34 阅读1分钟

一道经典算法,也是vue3diff算法优化手段之一

function getSequence (arr) {
    const result = []
    // 记录前驱节点
    const map = new Map()

    for (let i = 0; i<arr.length; i++) {
        const item = arr[i]
        if (result.length === 0) {
            result.push(i)
            continue
        }

        // 如果当前这一项大于arr数组的最后一项,则直接push
        const lastIndex = result[result.length - 1]
        const lastItem = arr[lastIndex]
        // 如果当前节点,大于 result的最后一个节点,则直接push
        if (item > lastItem) {
            // 记录前驱节点
            map.set(i, lastIndex)
            result.push(i)
            continue
        }

        let left = 0
        let right = result.length - 1 
        // 二分查找
        while (left < right) {
            // 计算出中间值
            const mid = Math.floor((left + right) / 2)
            const midItem = arr[result[mid]]
            // 如果中间值小于item,则头指针向右走
            if (midItem < item) {
                left = mid + 1
            } 
            // 否则尾指针 = 中间值
            else {
                right = mid
            }
        }

        if (arr[result[left]] > item) {
            if (left > 0) {
                map.set(i, result[left - 1])
            }
            // 找到最合适的,把索引替换进去
            result[left] = i
        }
    }



    // 反向追踪
    let l = result.length
    let last = result[l - 1]

    while (l > 0) {
        l--
        result[l] = last
        last = map.get(last)
    }

    return result
}