定义一个数组
d
p
dp
dp 存储最长递增子序列的长度,
d
p
[
n
]
dp[n]
dp[n]表示以
S
n
S_n
Sn 结尾的序列的最长递增子序列长度。
可以使用二分查找将时间复杂度降低为
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN)。
d
p
[
n
]
=
m
a
x
(
1
,
d
p
[
i
]
+
1
)
dp[n] = max(1,dp[i] + 1)
dp[n]=max(1,dp[i]+1)
S
i
<
S
n
S_i < S_n
Si<Sn and
i
<
n
i < n
i<n
对于一个长度为 N 的序列,最长递增子序列并不一定会以
S
n
S_n
Sn 为结尾,因此
d
p
[
N
]
dp[N]
dp[N] 不是序列的最长递增子序列的长度,需要遍历
d
p
dp
dp 数组找出最大值才是所要的结果.
m
a
x
(
d
p
[
i
]
,
1
<
=
i
<
=
N
)
max( dp[i] , 1 <= i <= N)
max(dp[i],1<=i<=N)即为所求。
int lengthOfLIS_1(vector<int> nums) {
int n = nums.size();
int dp[n];
int maxx = 1;
memset(dp,0,sizeof(dp));
for (int i = 0; i < n; i++) {
int maxn = 1;
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
maxn = max(maxn, dp[j] + 1);
}
}
dp[i] = maxn;
maxx = max(maxn,maxx);
}
return maxx;
}
int main(){
int a[] = {2,6,3,9,2,1,2,3,4,5};
vector<int> v;
int n = 10;
for(int i = 0;i < n;i++)
v.push_back(a[i]);
cout<<lengthOfLIS_1(v)<<endl;
}
但是时间复杂度为
O
(
N
2
)
O(N^2)
O(N2),有更快的方法,可以在搜索的时候,记录当前的最长递增子序列路径,每走一步,进行一次二分查找,然后更新数组。因为中间是二分搜索了,所以时间复杂度为
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN)
数组为:{2,6,3,9,2,1,2,3,4,5},每次输出的tail数组如下:
#include <bits/stdc++.h>
using namespace std;
int binarySearch(int tails[], int len, int key) {
int l = 0, h = len;
while (l < h) {
int mid = l + (h - l) / 2;
if (tails[mid] == key) {
return mid;
} else if (tails[mid] > key) {
h = mid;
} else {
l = mid + 1;
}
}
return l;
}
int lengthOfLIS(vector<int> nums) {
int n = nums.size();
int tails[n+1];
int len = 0;
for (int num : nums) {
int index = binarySearch(tails, len, num);
tails[index] = num;
if (index == len) {
len++;
}
}
return len;
}
int main(){
int a[] = {2,6,3,9,2,1,2,3,4,5};
vector<int> v;
int n = 10;
for(int i = 0;i < n;i++)
v.push_back(a[i]);
cout<<lengthOfLIS(v)<<endl;
}