673.最长递增子序列
思路:动态规划
dp[i]
表示nums[i]时最长递增子序列的长度
初始状态dp[0]=0;用一个j去遍历以nums[i]之前所有子序列的起点
cnt[i]
记录对应dp下最长子序列的个数
状态转移方程:
(1)如果nums[j] >= nums[i]
,非递增 不考虑
(2)如果nums[j] < nums[i]
,此时是递增,那么到 i 最长的子序列= 到 j 最长的子序列 + nums[i] ,dp[i] = dp[j] + 1
对于cnt和maxL的维护
(1)dp[i] > dp[j] + 1
时,maxL不变
(2)dp[i] = dp[j] + 1
时,maxL相等,且出现长度相同的不同最长子序列,此时cnt需要改变
(3)dp[i] < dp[j] + 1
,maxL需要更新变为dp[j] + 1
,cnt要重置到新的cnt[j]
cnt[j]的含义为以j做结尾的最长递增子序列个数,
如果cnt[j]=2
,再加一个新的nums[i]
加入递增子序列,那么cnt[i]
的个数是cnt[j]+1
,即3
那么在情况(2)中对cnt的维护:遍历j
时,有不同的j
结尾的子序列新增nums[i]
后最大长度相同,那么需要现有的cnt[i]+cnt[j]
(实际上相当于所有能和nuns[i]
组成最长递增子序列的cnt[j]
的和,起一个累加效果)
最后再设置一个maxL置,不断比较每一个dp[i],
(1)maxL<dp[i]
,更新maxL=dp[i]
并重新计数,res=cnt[i]
(2)maxL==dp[i]
,cnt需要累加,res=res+cnt[i]
;
(2)maxL>dp[i]
,无意义
代码:
cpp
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n=nums.size();
//初始化为1,至少单个字符可以当作子序列
vector<int>dp(n,1);
vector<int>cnt(n,1);
int counter=1;
int maxL=1;
int res=0;
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
//递增
if(nums[i]>nums[j]){
//对cnt进行计算
if(dp[i]<dp[j]+1){ //最大值变化
dp[i]=dp[j]+1;
//重置cnt,到j结尾的最大子序列也可能有多个,所以不是重置到1
cnt[i]=cnt[j];
}else if(dp[i]==dp[j]+1){//最大值相同的多一个
//cnt+1
cnt[i]=cnt[i]+cnt[j];
}
}
}
if(dp[i]>maxL){
maxL=dp[i];
res=cnt[i];
}else if(dp[i]==maxL){
res=res+cnt[i];
}
}
return res;
}
};