上一题只需要知道最长递增子序列的长度就行了,那样的话直接一个dp就完事了,但是呢,这里说了需要记录这个最长长度递增子序列的个数,这下的话,如果你想用原先的思路,其实可以,但是要能做到计数的话,需要你再定义一个数组cnt用来记录以numsi为尾的最长子序列个数。
思路:首先我们根据最长递增子序列的思路,知道dp是用来记录以numsi为尾的最长子序列长度的,那么我们要在动态规划实现递推的同时实现cnt计数。
我们开for循环直接从0开始就行了,因为不需要顾及特殊情况n=0或n=1,由于我们是需要实现nums的数组遍历的,所以从0开始就好。然后就直接照着上一题的思路直接抄上,直到我们判断numsi与numsj的大小时,开始不一样:
当我们判断numsi>numsj时,说明我们是可以把当前numsi接到以numsj为尾的子序列上的,由于我们需要计数的操作,所以不会使用max函数。这时就是判断dpi与dpj+1的大小,如果后者大,那么就更新dpi,它的个数cnti也随之更新到cntj(cnti在初始时是1,我们直接初始化就行);我们还需要判断dpi==dpj+1的可能性。为什么呢?当我们加上这numsi这一个数的时候这个以numsj结尾的子序列才刚刚和dpi的个数相等,那也就是相当于子序列长度为dpi的子序列又多了cntj个,可以想一下,细品一下。这个时候,cnti+=cntj,这时才是dpi所代表的个数。
然后在我们判断完dpi之后,我们需要做一个比较,也就是对于目前最长长度的比较。如果说这个时候dpi比目前最长长度还要大,那么dpi就是新的最长长度,那么记录的最长长度递增子序列的个数也就是dpi所对应的cnti的个数了,就不用之前的那个个数了,直接覆盖掉。
如果说我们这个时候dpi==目前的最长长度,也就是说目前最长长度的子序列个数又多了dpi个,和上面的思路一样,直接把当前记录的子序列个数+cnti。这样一直更新代换下去。
上代码:
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n=nums.size();
int res=INT_MIN;
vector<int>dp(n);
vector<int>cnt(n);
int len=0;
int count=0;
for(int i=0;i<n;i++){
dp[i]=1;
cnt[i]=1;
for(int j=0;j<i;j++){
if(nums[i]>nums[j]){
if(dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
cnt[i]=cnt[j];
}
else if(dp[j]+1==dp[i])
cnt[i]+=cnt[j];
}
}
if(dp[i]>len){
len=dp[i];
count=cnt[i];
}
else if(dp[i]==len)
count+=cnt[i];
}
return count;
}
};