LeetCode 673. 最长递增子序列的个数

给定一个未排序的整数数组,找到最长递增子序列的个数。

示例 1:

输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。

示例 2:

输入: [2,2,2,2,2]
输出: 5
解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。

注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数。

 【分析】

定义 dp(n,1) cnt (n,1) 

这里我用dp[i]表示以nums[i]为结尾的递推序列的长度,用cnt[i]表示以nums[i]为结尾的递推序列的个数,初始化都赋值为1,只要有数字,那么至少都是1。

从头开始遍历数组,对于每个遍历到的数字nums[i],我们再遍历其之前的所有数字nums[j],当nums[i]小于等于nums[j]时,不做任何处理,因为不是递增序列,直接continue。

反之,则判断dp[i]和dp[j]的关系,如果dp[i]等于dp[j] + 1,说明当前 j 加上 nums[i] 和之前存的最长序列长度一样 ,那么cnt[i] 中存的这个长度的序列个数就应该更新为新发现的数量加上之前的数量。如果dp[i]小于dp[j] + 1,说明我们找到了一条长度更长的递增序列,那么我们此时奖dp[i]更新为dp[j]+1,并且原本的递增序列都不能用了,直接用cnt[j]来代替。维护一个全局最长的子序列长度maxlen,每次都进行更新,到最后遍历一遍每个节点,如果长度等于maxlen,则加上对应这个长度的个数,最后返回。

【代码】

class Solution {
public:
    int findNumberOfLIS(vector& nums) {
        int n = nums.size();
        int maxlen = 1;
        int res = 0;
        vector cnt(n,1);
        vector dp(n,1);
        for(int i = 1; i < n; ++i){
            for(int j = 0 ;j < i; ++j){
                if(nums[j] >= nums[i]) continue;
                if (dp[i] == dp[j] + 1)//当前序列和之前存的最长序列长度一样 
                    cnt[i] += cnt[j];//把这个长度的之前和现在的个数加起来
                else if (dp[i] < dp[j] + 1) {//找到一个更长的序列
                    dp[i] = dp[j] + 1;//长度加1
                    cnt[i] = cnt[j];//之前的那个数目用不了,只能用新的这个数量
                }
            }
            maxlen = max(maxlen,dp[i]);
        }
        for(int i = 0; i < n; ++i){
            if(dp[i] == maxlen)
                res += cnt[i];
        }
        return res;
    }
};

【总结】动态规划的题真的很烧脑..... 

 

你可能感兴趣的:(LeetCode,数据结构和算法)