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


题目来源

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] <= 106

相似题目

题号 题目 标签
673 最长递增子序列的个数 子序列;递增
300 最长上升子序列 子序列;递增
674 最长连续递增序列 子序列;递增
354 俄罗斯套娃信封问题 子序列;递增

题解分析

解法一:动态规划

  1. 本题是典型的动态规划题目,而且本题与最长上升子序列极度相似,但是本题有一些不同点,那就是它不是要求最长递增子序列的长度,而是要求最长递增子序列的个数。
  2. 我们知道,单靠最长上升子序列中定义的dp[i]无法记录最长递增子序列的个数,所以,我们这里需要再定义一个数组cnts[n]用以记录最长递增子序列的个数。
  3. dp数组的动态转移是比较容易的,那cnts数组的状态转移如何进行呢?实际上,我们可以仿照dp状态转移的思路来转移cnts数组的状态。具体来说,在找到新的上升子序列时,cnts数组需要重置为cnts[j],而如果找到相同长度的递增子序列时,则需要累加cnts[j]表示最长递增子序列的个数增加了。
class Solution {
    
    public int findNumberOfLIS(int[] nums) {
        int n = nums.length;
        // dp[i]表示以i结尾的最长递增子序列长度
        int[] dp = new int[n];
        // cnts[i]表示以i结尾的最长递增子序列的个数
        int[] cnts = new int[n];
        // 记录最长值
        int maxs = 0;
        // 记录最长递增子序列的个数
        int ans = 0;
        for(int i=0; i nums[j]){
                    if(dp[j] + 1 > dp[i]){
                        // 此时原来的递增子序列并不是最长的,需要更新
                        dp[i] = dp[j] + 1;
                        cnts[i] = cnts[j];// 重置cnts[i]
                    }else if(dp[j] + 1 == dp[i]){
                        // 出现一个相同长度的最长递增子序列
                        cnts[i] += cnts[j];
                    }
                }
            }
            if(dp[i] > maxs){
                maxs = dp[i];
                ans = cnts[i];
            }else if(dp[i] == maxs){
                // 出现相同长度的自增子序列
                ans += cnts[i];
            }
        }
        return ans;
    }
}