【LeetCode_673】最长递增子序列的个数

题目描述:

解释:这道题是力扣第三百题——最长上升子序列的进阶,与之不同的是300题要求的是最长上升子序列的长度,而这题需要我们求最长上升子序列的个数。我们可以借助动态规划来解决这道题。

首先定义一个一维数组dp[i],表示考虑前i个数字的最长上升子序列的长度。然后,题目由于要求最长的上升子序列的数目,所以我们需要维护另一个数组count[i],表示前i个数字长度为dp[i]的子序列的个数。

class Solution {
public:
    int findNumberOfLIS(vector<int>& nums) {
        int n=nums.size();
        vector<int> dp(n+1,1);
        vector<int> count(n+1,1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++){
                if(nums[j-1]<nums[i-1]){
                    if(dp[j]>1+dp[i]){  //[0:i]有1个最长子序列
                        dp[i]=1+dp[j];
                        count[i]=count[j];
                    }
                    else if(dp[i]==dp[j]+1){ //[0:i]有多个最长子序列
                        count[i]+=count[j];
                    }
                }
            }
        }
        int longest=0;
        int ret=0;
        for(int i=1;i<=n;i++){
            longest=max(longest,dp[i]);
        }
        for(int i=1;i<=n;i++){
            if(longest==dp[i]){
                ret+=count[i];
            }
        }
        return ret;
    }
};

我们重点来看这一段:

if(nums[j-1]<nums[i-1]){
    if(dp[j]>dp[i]+1){  //[0:i]有1个最长子序列
        dp[i]=1+dp[j];
        count[i]=count[j];
    }
    else if(dp[i]==dp[j]+1){ //[0:i]有多个最长子序列
        count[i]+=count[j];
    }
}

在nums[j-1]<nums[i-1]的情况下,如果dp[j]>=dp[i],也就是说在[0:i-1]内找到了一个更长的子串,此时count[i]自然就要等于count[j]

如果在[0, i-1]的范围内,找到了j,使得dp[j] + 1 == dp[i],说明找到了两个相同长度的递增子序列。那么以i为结尾的子串的最长递增子序列的个数 就应该加上以j为结尾的子串的最长递增子序列的个数,即:count[i] += count[j];

  • 时间复杂度:O(N2)。N为nums的长度。
posted @ 2022-02-25 21:06  天涯海角寻天涯  阅读(34)  评论(0)    收藏  举报