首页 > 试题广场 >

最长上升子序列(三)

[编程题]最长上升子序列(三)
  • 热度指数:76374 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定数组 arr ,设长度为 n ,输出 arr 的最长上升子序列。(如果有多个答案,请输出其中 按数值(注:区别于按单个字符的ASCII码值)进行比较的 字典序最小的那个)

数据范围:
要求:空间复杂度 ,时间复杂度
示例1

输入

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

输出

[1,3,4,8,9]
示例2

输入

[1,2,8,6,4]

输出

[1,2,4]

说明

其最长递增子序列有3个,(1,2,8)、(1,2,6)、(1,2,4)其中第三个 按数值进行比较的字典序 最小,故答案为(1,2,4)         

备注:

简单版本得到序列

我们知道通过贪心+二分可以求出最长递增子序列的长度,但由于每次更新len长度序列的结尾元素,导致了dp数组是真,结果不是最长的递增子序列,只能保证最长递增子序列的结尾元素。既然知道了失真的原因,那么就可以另外建立一个数组,在每次失真操作前保存序列。
具体:

  • 当更新dp最后一个元素时,应该保存dp数组,此时数组是当前最大长度的未失真序列。
  • 当dp数组长度增加时,应该在res数组后加上此元素,res.push(arr[i])
function LIS( arr ) {
    const dp = [];
    let res = [];
    for (let i=0; i<arr.length; ++i) {
        let r = dp.length-1, l = 0;
        let pos = dp.length;
        while(l <= r) {
            const mid = Math.floor((r - l) / 2) + l; 
            if (dp[mid] >= arr[i]) {
                r = mid-1;
                pos=mid;
            } else if (dp[mid] < arr[i]){
                l = mid+1;
            }
        }
        // 获得递增序列
        if(pos===dp.length) {
            res.push(arr[i]);
        } else if (pos === dp.length-1) {
            res[res.length-1] = arr[i];
        }
        dp[pos] = arr[i];
    }
    return res;
}
发表于 2022-01-31 12:08:47 回复(1)

超时版:

function LIS( arr ) {
    if (arr === null || arr.length === 0) return 0;
    const dp = new Array(arr.length).fill(1);
    let max = 1;
    for (let i = 1; i < arr.length; i++) {
        for (let j = 0; j < i; j++) {
            if (arr[i] > arr[j]) {
                dp[i] = Math.max(dp[i], dp[j] + 1);
                max = Math.max(max, dp[i]);
            }
        }
    }
    const result = new Array(max);
    for (let i = dp.length - 1; i >= 0; i--) {
        if (dp[i] === max) result[--max] = arr[i];
    }
    return result;
}

通过版:

function LIS( arr ) {
    const list = new Array(arr.length + 1);
    const maxLen = new Array(arr.length);
    let n = 1;
    list[1] = arr[0];
    maxLen[0] = 1;
    for (let i = 0; i < arr.length; i++) {
        if (list[n] < arr[i]) {
            list[++n] = arr[i];
            maxLen[i] = n;
        } else {
            const index = binarySearch(list, n, arr[i]);
            list[index] = arr[i];
            maxLen[i] = index;
        }
    }
    const result = new Array(n);
    for (let i = maxLen.length - 1; i >= 0; i--) {
        if (maxLen[i] === n) result[--n] = arr[i];
    }
    return result;
}
function binarySearch(arr, right, key) {
    let left = 0;
    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        if (arr[mid] >= key) right = mid - 1;
        else left = mid + 1;
    }
    return left;
}
编辑于 2021-03-25 11:40:59 回复(0)

问题信息

难度:
2条回答 16792浏览

热门推荐

通过挑战的用户

查看代码
最长上升子序列(三)