每日一题:最长上升子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度。

实例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n^2) 。

进阶:你能将算法的时间复杂度降低到 O(n log n) 吗?

很容易想到动态规划算法,可以达到 O ( n 2 ) O(n^2) 的时间复杂度。
采用自底向上的动态规划。
状态方程:
f(x) = 以x为起点的最长子序列;
f(x) = 1 + f(y), y > x;
f(x) = 1, x 大于它后面的所有元素;
第一层循环遍历数组,第二层循环找到比当前元素大的元素,再依次比较得出最长子序列。所以时间复杂度为 O ( n 2 ) O(n^{2})

class Solution {
public:

    int lengthOfLIS(vector<int>& nums) {
        if (nums.empty()) return 0;
        int numsLen = nums.size(), maxLen = 1;
        vector<int> dptable(numsLen, 1);
        for (int i = numsLen - 2; i >= 0; i--){
            int temp = i + 1;
            while (temp < numsLen){
                if (nums[i] < nums[temp]){
                    dptable[i] = max(dptable[i], dptable[temp] + 1);
                }
                temp++;
            }
            maxLen = max(maxLen, dptable[i]);
        }
        return maxLen;
    }
};

如果使用贪心的思路,可以实现O(nlogn)时间复杂度的算法

思路:如果我们要使上升子序列尽可能的长,则我们需要让序列上升得尽可能慢,因此我们希望每次在上升子序列最后加上的那个数尽可能的小。

维护一个数组d[i],表示长度为i的最长上升子序列的末尾元素的最小值,用len记录目前最长上升子序列的长度,起始时len为1,d[1] = nums[0]。易证d[i]是关于i的递增序列。

算法流程:
len初始化为1,从前往后遍历数组nums,在便利到nums[i]时:如果nums[i]>d[len],则直接加入到d数组末尾,并更新len=len+1;否则,在d数组1到len的部分进行二分查找(因为是有序数组所以可以进行二分查找),找到第一个比nums[i]小的数d[k],并更新d[k+1] = nums[i];

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int len = 1, n = (int)nums.size();
        if (0 == n){
            return 0;
        }
        vector<int> d(n+1);
        d[len] = nums[0];
        for (int i = 1; i < n; i++){
            if (nums[i] > d[len]){
                d[++len] = nums[i];
            }
            else{ // 进行二分查找,找到第一个比nums[i]小的数d[k];
                // 如果找不到说明所有的数都比nums[i]大,此时要更新d[1],将pos设为0
                int left = 1, right = len, pos = 0;
                while (left <= right){
                    int mid = (left + right) / 2;
                    if (d[mid] < nums[i]){
                        pos = mid;
                        left = mid + 1;
                    }
                    else {
                        right = mid - 1;
                    }
                }
                d[pos + 1] = nums[i];
            }
        }
        return len;
    }
};
发布了76 篇原创文章 · 获赞 10 · 访问量 8262

猜你喜欢

转载自blog.csdn.net/weixin_38742280/article/details/104855577
今日推荐