673. 最长递增子序列的个数(dp)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了673. 最长递增子序列的个数(dp)相关的知识,希望对你有一定的参考价值。
673. 最长递增子序列的个数(dp)
方法1:dp
在用 O ( n 2 ) O(n^2) O(n2) 求 L I S LIS LIS的长度时维护一个 c n t i cnt_i cnti 表示以 i i i结尾的 L I S LIS LIS的个数,然后再维护一个 m a x L e n , a n s maxLen,ans maxLen,ans即可。
时间复杂度: O ( n 2 ) O(n^2) O(n2)
class Solution {
public:
int findNumberOfLIS(vector<int>& a) {
int n=(int)a.size();
vector<int>f(n+1),g(n+1);
int mx=0,ans=0;
for(int i=1;i<=n;i++){
f[i]=g[i]=1;
for(int j=1;j<i;j++){
if(a[i-1]>a[j-1]){
if(f[j]+1>f[i]){
f[i]=f[j]+1;
g[i]=g[j];
}
else if(f[j]+1==f[i]){
g[i]+=g[j];
}
}
}
if(f[i]>mx){
mx=f[i];
ans=g[i];
}
else if(f[i]==mx) ans+=g[i];
}
return ans;
}
};
方法2:二分+前缀和+贪心。
这个方法比较妙,需要维护两个二维数组。
一个
d
(
i
,
j
)
d(i,j)
d(i,j) 表示长度为
i
−
1
i-1
i−1的
L
I
S
LIS
LIS的第
j
j
j个末尾元素,
d
i
d_i
di中的数是非递增的。
c n t ( i , j ) cnt(i,j) cnt(i,j) 是对应 d ( i , j ) d(i,j) d(i,j)的 L I S LIS LIS前缀和。
每次我们对于当前数 n u m num num 二分找到 d i d_i di 满足 d [ i ] . b a c k ( ) ≥ n u m d[i].back() \\ge num d[i].back()≥num 的最小位置 p p p。
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
class Solution {
int binarySearch(int n, function<bool(int)> f) {
int l = 0, r = n;
while (l < r) {
int mid = (l + r) / 2;
if (f(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
public:
int findNumberOfLIS(vector<int> &nums) {
vector<vector<int>> d, cnt;
for (int v : nums) {
int i = binarySearch(d.size(), [&](int i) { return d[i].back() >= v; });
int c = 1;
if (i > 0) {
int k = binarySearch(d[i - 1].size(), [&](int k) { return d[i - 1][k] < v; });
c = cnt[i - 1].back() - cnt[i - 1][k];
}
if (i == d.size()) {
d.push_back({v});
cnt.push_back({0, c});
} else {
d[i].push_back(v);
cnt[i].push_back(cnt[i].back() + c);
}
}
return cnt.back().back();
}
};
以上是关于673. 最长递增子序列的个数(dp)的主要内容,如果未能解决你的问题,请参考以下文章
Leetcode-673 (Number of Longest Increasing Subsequence)最长递增子序列的个数