《LeetCode之每日一题》:107.最长递增子序列

Posted 是七喜呀!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《LeetCode之每日一题》:107.最长递增子序列相关的知识,希望对你有一定的参考价值。

最长递增子序列


题目链接: 最长递增子序列

有关题目

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。
例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4
示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1
提示:

1 <= nums.length <= 2500
-10^4 <= nums[i] <= 10^4

题解

法一:动态规划

思路:
dp[i]:表示前i个(包含i)数组元素中升序最大递增子序列
int lengthOfLIS(int* nums, int numsSize){
    int dp[numsSize];
    int ans = 0;
    for (int i = 0; i < numsSize; i++){
        dp[i] = 1;//初始化为1
        for (int j = 0; j < i; j++){
            if (nums[j] < nums[i]){
            //nums 10 9 2 5 3 7 101
            //dp 1 1 1 2 2 3 4
                dp[i] = fmax(dp[i],dp[j] + 1);
            }
        }
        ans = fmax(ans,dp[i]);//记录最大值
    }
    return ans;
}


方法二:贪心 + 二分查找

思路:贪心,使上升子序列尽可能的长
序列上升得尽可能慢,因此我们希望每次在上升子序列最后加上的那个数尽可能的小

数组 d[i]表示长度为 i 的最长上升子序列的末尾元素的最小值,
即在数组 1,2,3,4,5,6中长度为3的上升子序列
可以为 1,2,3也可以为 2,3,4等等但是d[3]=3,
即子序列末尾元素最小为3

代码一:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        int len = 1;
        vector d(n + 1, 0);
        d[len] = nums[0];//初始化长度为 1 的最长上升子序列的末尾元素的最小值为nums[0]
        for (int i = 1; i < nums.size(); i++){
            if (nums[i] > d[len]){
                d[++len] = nums[i];
            }
            else{
                int l = 1, r = len, pos = 0; 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
                while(l <= r){
                    int mid = (l + r) >> 1;
                    if (nums[i] > d[mid]){//找到小于nums[i]的
                        pos = mid;
                        l = mid + 1;
                    } else {
                        r = mid - 1;
                    }
                }
                d[pos + 1] = nums[i];//下一个位置就是大于等于nums[i]的
            }
        }
        return len;//vector开辟d时,可以直接返回d.size();
    }
};

代码二:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int> d;
        for (int& num : nums){
            auto it = lower_bound(d.begin(), d.end(), num);//注意lower_bound与up_bound的用法
            //前者找到大于等于num的数,后者找到大于num的数
            if (it != d.end()){
                *it = num;
            }
            else
                d.push_back(num);
        }
        return d.size();
    }
};

代码三:C

int lower_bound(int d[], int dSize, int target){
    int l = 0, r = dSize - 1, pos = dSize;
    while(l <= r){
        int mid = (l + r) >> 1;
        if (d[mid] >= target){
            pos = mid;
            r = mid - 1;
        } else {
            l = mid + 1;
        }
    }
    return pos;
}

int lengthOfLIS(int* nums, int numsSize){
    int d[numsSize], dSize = 1;
    d[0] = nums[0];
    for (int i = 1; i < numsSize; i++){
        int num = nums[i];
        int it = lower_bound(d,dSize,num);//找到第一个大于等于
        if (it != dSize){
            d[it] = num;
        } else {
            d[dSize++] = num;
        }
    }
    return dSize;
}

以上是关于《LeetCode之每日一题》:107.最长递增子序列的主要内容,如果未能解决你的问题,请参考以下文章

leetcode 1月12日每日一题 334. 递增的三元子序列

leetcode 1月12日每日一题 334. 递增的三元子序列

《LeetCode之每日一题》:264.递增的三元子序列

《LeetCode之每日一题》:213.最长和谐子序列

《LeetCode之每日一题》:65.最长回文子串

《LeetCode之每日一题》:106.最长公共子序列