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

示例 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位有符号整数。

Related Topics
  • 树状数组
  • 线段树
  • 数组
  • 动态规划

  • 👍 478
  • 👎 0
  • 参考之前的LeetCode刷题【300】最长递增子序列这题,用动态规划的话先拿出原来的代码看下

    class Solution {
        public int lengthOfLIS(int[] nums) {
            int[] dp = new int[nums.length];
            int max = 0;
            for (int i = 0; i < nums.length; i++) {
                dp[i] = 1;
                for (int j = 0; j < i; j++) {
                    if (nums[i]<=nums[j]){
                        continue;
                    }
                    dp[i] = Math.max(dp[j]+1,dp[i]);
                }
                max = Math.max(max,dp[i]);
            }
            return max;
        }
    }

    在原来的dp数组记录的到达每个位置的时候,需要额外的增加一个数组int[] count来记录当前位置的最大值,下面以数组[1,2,4,3,5,4,7,2]为例

    1. 第一位的时候,dp[0] = 1,count[0] = 1,显然的第一位的时候递增子序列长度为1,就是自身,可能的子序列组合也只有一种
    2. 当索引1的时候,dp[1] = 2,count[1] = 1,因为当前位置上的值2比前面的1大,构成新的最长递增子序列,所以长度增加,组合情况也只有1种
    3. 当索引2的时候,此时的值为4,依次从头开始遍历后,可以知道最大递增子序列长度为3,最大递增子序列组合数为1。
    4. 当索引3的时候,此时的值为3,只能喝前面的2组成最大递增子序列,同样的和末尾为4的时候的组合长度一样,最大递增子序列长度为3,当前位置以数字3结尾的组合只有[1,2,3]一种,所以count[3] = 3
    5. 当索引4的时候,当前位置数字位5,以5结尾的最大递增子序列的可以为[1,2,4,5]或者[1,2,3,5],显然的此时的dp[4]可以由原来的dp[2]+1 也可以由dp[3]+1得到,那么当遍历到索引2的时候可以得到dp[4] = dp[2]+1,此时同时把count[4] = count[2],之后再次遇到dp[3]+1 == dp[4]的时候,count[4] 应该等于count[3]+count[4]的合。即dp[4] = 4 ,count[4] = 2
    6. 当索引5的时候位置上的值为4,能和前面的组成[1,2,3,4]最大递增子序列,其dp值依赖于前面的值3的索引处的dp,即dp[5] = dp[3]+1 = 4,子序列个数同样继承count[5] = count[3] = 1,那么这个时候,我们在遍历比价max的时候就会发现和前面的索引4位置求到的max值相等,都是4,这个时候就需要额外记下maxCount = count[4]+count[5] = 2 + 1 = 3;
    7. 索引6,位置上的值为7,dp值依赖于索引4、5位置上的值,当一开始遍历的索引4的时候dp[6] = dp[4]+1 = 5,count[6] = count[4] = 2,当之后遍历到索引5嘚 时候,dp[5]+1 == dp[6] ,所以count[6] = count[6] + count[5] = 2 + 1 = 3。
    8. 索引7,值为2,省略不写了

    数组12435472
    dp[]12334452
    count[]11112131

    所以代码逻辑基本就出来了

    class Solution {
        public int findNumberOfLIS(int[] nums) {
            int[] dp = new int[nums.length];
            int[] count = new int[nums.length];
            int maxCount = 0;
            int max = 0;
            for (int i = 0; i < nums.length; i++) {
                dp[i] = 1;
                count[i] = 1;
                for (int j = 0; j < i; j++) {
                    if (nums[j] >= nums[i]){
                        //前面的这个数字比当前数字大,跳过
                        continue;
                    }
                    if (dp[j]+1 > dp[i]){
                        dp[i] = dp[j]+1;
                        count[i] = count[j];
                    }else if (dp[j]+1 == dp[i]){
                        count[i] += count[j];
                    }
                }
                if (max < dp[i]){
                    max = dp[i];
                    maxCount = count[i];
                }else if (max == dp[i]){
                    maxCount += count[i];
    
                }
            }
            return maxCount;
        }
    }