Number of Longest Increasing Subsequence 最长递增子序列的个数

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

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

思路:这道题采用动态规划,如果我们维护一个一维数组dp,且dp[i]表示第i个下标的元素的最长递增子序列的个数,这样定义的话动态规划的递推方程比较难找,因为比如这个例子:

[1,3,5,4,7]

dp[0]=1,dp[1]=1,dp[2]=1,dp[3]=1,dp[4]=2。因为还要考虑子序列长度的信息,对于dp[4]很难判断等于哪两个子序列的和(题目中是dp[2]和dp[3]),所以直观的我们还需要一个维护另外一个长度的数组len。所以基本思路如下:

我们维护两个一维数组,len和cnt,len[i]表示以nums[i]结尾的最长递增数组的长度,cnt[i]表示以nums[i]结尾的最长递增数组的个数。那么我们需要两层循环,外循环遍历数组nums,对于固定的nums[i],内循环判断在nums[i]之前的元素nums[j],如果nums[i]>nums[j],那么判断len[j]+1是否大于len[i],如果大于意味着找到了更长的子序列,那么len[i]=len[j]+1,且把cnt[i]=cnt[j],如果len[j]+1等于len[i],意味着出现了上图中例子的情况,我们找到了相同长度的两个子序列,那么更新cnt[i]为cnt[i]+cnt[j]。最后我们再次遍历数组nums,找到长度最大的len[i]对应的cnt[i]累加起来即可。

参考代码:

class Solution {
public:
    int findNumberOfLIS(vector<int>& nums) {
	vector<int> len(nums.size(), 1);
	vector<int> cnt(nums.size(),1);
	int res = 0;
	int mx = 0;
	int n = nums.size();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < i; j++) {
			if (nums[j] < nums[i]) {
				if ((len[j] + 1)==len[i]) {
					cnt[i]+=cnt[j];
				}
				else if ((len[j] + 1) > len[i]) {
					cnt[i] = cnt[j];
                    len[i] = len[j] + 1;
				}
			}
		}
	}
	for (int i = 0; i < nums.size(); i++) {
		if (len[i] >= mx) {
			if (len[i] > mx) {
				mx = len[i];
				res = cnt[i];
			}
			else {
				res += cnt[i];
			}
		}
	}
	return res;        
    }
};





猜你喜欢

转载自blog.csdn.net/qq_26410101/article/details/80881284