29.最长递增子序列的个数(medium)

1.题目链接:

673. 最长递增子序列的个数 - 力扣(LeetCode)673. 最长递增子序列的个数 - 给定一个未排序的整数数组 nums , 返回最长递增子序列的个数 。注意 这个数列必须是 严格 递增的。 示例 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。 提示:  * 1 <= nums.length <= 2000 * -106 <= nums[i] <= 106https://leetcode.cn/problems/number-of-longest-increasing-subsequence/description/

2.题目描述:

给定一个未排序的整数数组 nums , 返回最长递增子序列的个数 。​     注意 这个数列必须是 严格 递增的。​

示例 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。​
3. 解法(动态规划):
算法思路:
1. 状态表示:
        先尝试定义一个状态:以 i  为结尾的最长递增子序列的「个数」。那么问题就来了,我都不知道i  为结尾的最长递增子序列的「长度」是多少,我怎么知道最长递增子序列的个数呢?​                                  因此,我们解决这个问题需要两个状态,一个是「长度」,一个是「个数」:
          len[i]  表示:以 i  为结尾的最长递增子序列的长度;​
          count[i]  表示:以 i  为结尾的最长递增子序列的个数。​

2. 状态转移方程:
        求个数之前,我们得先知道长度,因此先看 len[i] :​

i.

在求 i  结尾的最长递增序列的长度时,我们已经知道 [0, i - 1]  区间上的 len[j]

                信息,用 j  表示 [0, i - 1]  区间上的下标;​
  ii. 我们需要的是递增序列,因此 [0, i - 1]  区间上的 nums[j]  只要能和 nums[i]                      构成上升序列,那么就可以更新 dp[i]  的值,此时最长长度为 dp[j] + 1 ;​        iii. 我们要的是 [0, i - 1]  区间上所有情况下的最大值。​
综上所述,对于 len[i] ,我们可以得到状态转移方程为:​
len[i] = max(len[j] + 1, len[i]) ,其中 0 <= j < i ,并且 nums[j] < nums[i]

在知道每一个位置结尾的最长递增子序列的长度时,我们来看看能否得到 count[i] :​

i.

我们此时已经知道 len[i]  的信息,还知道 [0, i - 1]  区间上的 count[j]  信

       息,用 j  表示 [0, i - 1]  区间上的下标;​
ii. 我们可以再遍历一遍 [0, i - 1]  区间上的所有元素,只要能够构成上升序列,并且上                  升序列的长度等于 dp[i] ,那么我们就把 count[i]  加上 count[j]  的值。这样循          环一遍之后,count[i]  存的就是我们想要的值。​

综上所述,对于 count[i] ,我们可以得到状态转移方程为:​
count[i] += count[j] ,其中 0 <= j < i ,并且 nums[j] < nums[i] &&

dp[j] + 1 == dp[i]

3. 初始化:

对于 len[i] ,所有元素自己就能构成一个上升序列,直接全部初始化为 1 ;​
对于 count[i] ,如果全部初始化为 1 ,在累加的时候可能会把「不是最大长度的情况」累

加进去,因此,我们可以先初始化为 0 ,然后在累加的时候判断一下即可。具体操作情况看代码~​

4. 填表顺序:

毫无疑问是「从左往右」。

5. 返回值:

manLen  表示最终的最长递增子序列的长度。​
根据题目要求,我们应该返回所有长度等于 maxLen  的子序列的个数。​

Java算法代码:

class Solution {
    public int findNumberOfLIS(int[] nums) {
        // 1.创建dp表
        // 2.初始化
        // 3.填表
        // 4.返回值
        int n = nums.length;
        int[] len = new int[n];
        int[] count = new int[n];
        for(int i = 0; i < n; i++) len[i] = count[i] = 1;

        int retlen = 1, retcount = 1;
        for(int i = 1; i < n; i++){
            for(int j = 0; j < i; j++){
                if(nums[j] < nums[i]){
                    if(len[j] + 1 == len[i]) count[i] += count[j];
                    else if(len[j] + 1 > len[i]){
                        len[i] = len[j] + 1;
                        count[i] = count[j];
                    }
                }
            }
            if(retlen == len[i]) retcount += count[i];
            else if(retlen < len[i]){
                retlen = len[i];
                retcount = count[i];
            }
        }
        return retcount;
    }
}

运行结果:

动态规划:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值