leetcode每日一题系列-最长递增子序列的个数-「序列dp」

654 阅读1分钟

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

[博客链接]

菜🐔的学习之路

掘金首页

[题目链接]

题目链接

[github地址]

github地址

[题目描述]

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

示例 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。

思路一:序列dp

  • 常规序列dp的题
  • 因为求的是子序列的数量
  • 我们需要定义两个dp数组
    • dp[i] 表示以第i个字符为结尾的最长递增子序列的长度
    • cnt[i] 表示以第i字符为结尾的最长递增子序列的数量
  • dp转移过程分析
    • dp[0] = 1;
    • nums[i] > nums[j] 的时候dp[i] = dp[j]+1
    • 反之dp[i] = 1;
  • cnt转移过程分析
    • 与上述过程分析基本一致
    • cnt[0] =1 ;
    • nums[i] > nums[j] 的时候分两种情况判断
      • 判断当前元素是否可以拼在前面元素后面组成新的递增子序列
      • 如果可以也就是说**dp[i] == dp[j+1] **那么cnt[i] += cnt[j];
      • dp[i]< dp[j+1]则重置 cnt[i] = cnt[j];
  • 最后返回dp最大的对应的cnt数值即可
 public int findNumberOfLIS(int[] nums) {
           int[] dp = new int[nums.length];
           int[] cnt = new int[nums.length];
           dp[0] = 1;
           cnt[0] = 1;
           int max = 0;
           for(int i = 0;i < nums.length; i++){
               dp[i] = cnt[i] = 1;
               for(int j = 0; j < i;j++){
                   if(nums[i]> nums[j]){
                       if(dp[i]<dp[j]+1){
                           cnt[i]=cnt[j];
                           dp[i] = dp[j]+1;
                       }else if(dp[i]== dp[j]+1){
                           cnt[i]+=cnt[j];
                       }
                   }
               }
               max = Math.max(dp[i],max);
           }
           int res = 0;
           for(int i = 0; i < nums.length; i++){
               if(max == dp[i]){
                   res +=cnt[i];
               }
           }
           return res;

   }
  • 时间复杂度:O(n2n^2)
  • 空间复杂度:O(nn)