leetcode012-Number of Longest Increasing Subsequence

Given an unsorted array of integers, find the number of longest increasing subsequence.

Example 1:

Input: [1,3,5,4,7]
Output: 2
Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7].

Example 2:

Input: [2,2,2,2,2]
Output: 5
Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.

Note: Length of the given array will be not exceed 2000 and the answer is guaranteed to be fit in 32-bit signed int.


这道题明显是leetcode300. Longest Increasing Subsequence的变体。LIS是在最一个序列里找到最长的递增子序列的长度。

example: [84, -48, -33, -34, -52, 72, 75, -12, 72, -45]

  • scan from left to right,  the longest that ends at 84: [84] (1)
  •  ... ends at -48: [-48] (1)
  •  ... ends at -33: [-48, -33] (2)
  •  ... ends at -34: [-48, -34] (2)
  •  ... ends at -52: [-52] (1)
  •  ... ends at  72: [-48, -33, 72] or [-48, -34, 72] (3)
  •  ... ends at  75: [-48, -33, 72, 75] or [-48, -34, 72, 75] (4)
  •  ... ends at -12: [-48, -33, -12] or [-48, -34, 12] (3)
  •  ... ends at  72: [-48, -33, -12, 72] or [-48, -34, 12, 72] (4)
  •  ... ends at -45: [-48, -45], [-52,-45] (2)
通过观察我们可以发现,当我们寻找第i个位置的最长子序列长度时是通过遍历位置i左边所有数值小于nums[i]的位置,找出当中对应长度最大的一个,然后取那个数加1(相当于nums[i]续在它所能续(它必须比它想续的序列的最后一个位置的数大)的序列中的最长一条),我们用dp[i]记录位置当序列结束在位置i时,该序列的最大长度。

所有的元素都能自成一条序列,因此用1初始化dp数组。
dp[i] = max{dp[j]+1 | nums[i] > nums[j] }
 
解题思路:LIS的变体要求输出最长子序列的个数,因此我为每个位置增加一个变量dp[i].second来记录状态转移的方程中max{dp[j]+1}有多少个j同时符合跳转要求。
                  从当前位置往回扫描的过程中,一旦发现有比当前发现的最长“可续”序列更长的序列时,更新max值,更新from值。from值记录的是要多少条符合max值的子序列。如果发现是相同长度序列(即max值相等), 则from要在原基础上加上当前位置所能代表的几条子序列。
                  如果在往回扫描的过程中,并没有可续的子序列,则from值为0,dp[i].second不变保持为1。如果有可续的,则dp[i].second更新为from值所记录的条数。
 

    int findNumberOfLIS(vector<int>& nums) {
        // dp[i].first: the length of the longest increasing subsequence ends at string[i]
        vector<pair<int, int>> dp(nums.size(),make_pair(1, 1));
        int ans = 1;
        for (int i = 1; i < nums.size(); i++) {
            int max = 0;  // 用于更新左边符合要求的最长子序列的长度
            int from = 0;
            for (int j = i-1; j >= 0; j--) {
                if (nums[i] > nums[j]) {
                    if (dp[j].first > max) {
                        max = dp[j].first;
                        from = dp[j].second;
                    } else if (dp[j].first == max) {
                        from += dp[j].second;
                    }
                }
            }
            if (max != 0) {
                dp[i].first += max;
                dp[i].second = from;
            }
            // 最长子序列的长度更新
            if (dp[i].first > ans) ans = dp[i].first;
        }
        if (ans == 1) return dp.size();
        int sum = 0;
        for (int i = 0; i < dp.size(); i++) {
            if (dp[i].first == ans) {
                sum += dp[i].second;
            }
        }
        return sum;
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值