Leetcode:673. 最长递增子序列的个数
给定一个未排序的整数数组,找到最长递增子序列的个数。
示例 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位有符号整数。
解题思路:
动态规划中的最长子序列问题。首先得明白如何求解未排序数组的最长子序列问题。
求解未排序数组的最长子序列 == 求解以位置pos结尾的最长子序列长度dp[pos],return max(dp);
以位置pos结尾的最长子序列dp[pos]的求解方法:
- [0,pos-1]区间内,没有比nums[pos]小的值。dp[pos]=1;
- 如果在[0,pos-1]区间内存在nums[i]<nums[pos],那么选择该条件下,max(dp[i])+1。
- 遍历的过程中记录dp的max,最后返回max即可。
以上便是未排序数组的最长子序列的求解方法,结合本题,不过是需要记录最长子序列的个数而已,稍作修改即可。此刻
dp[pos]设置为pair<int,int>类型数据,first代表位置pos处结尾的最长子序列的长度,second代表个数。那么根据上述的三个过程将演变为下面的三个。
- [0,pos-1]区间内,没有比nums[pos]小的值。dp[pos]={1,1};
- 如果在[0,pos-1]区间内存在nums[i]<nums[pos],那么选择该条件下,dp[pos].first = max(dp[i].first),dp[pos].second=max(dp[i].second),应注意,可能有多个位置是最长。
- 遍历的过程中记录dp.first最大值对应的下标res,最后返回dp[res].second即可。
算法的时间复杂度是O(n^2),由于数组的规模不超过2000,因此是可以接受的。
class Solution { public: int findNumberOfLIS(vector<int>& nums) { int size = nums.size(), i,j; if(size==0) return 0; vector<pair<int, int>> dp(size, { 0,0 }); //{长度,个数} dp[0] = { 1,1 }; int all_max = 1, all_sum = 1; for (i = 2; i <= size;i++){ int sum = 0, max = 0; for (j = 1; j <= i - 1; j++) { if (nums[i - 1] > nums[j - 1]) { if (dp[j - 1].first == max) sum += dp[j - 1].second; else if (dp[j - 1].first > max) { max = dp[j - 1].first; sum = dp[j - 1].second; } } } dp[i - 1].first = max + 1; if (max == 0) sum = 1; dp[i - 1].second = sum; if (dp[i - 1].first == all_max) all_sum += dp[i - 1].second; if (dp[i - 1].first > all_max) { all_sum = dp[i - 1].second; all_max = dp[i - 1].first; } } return all_sum; } }; |