main
黄海 1 year ago
parent 915c85631a
commit 8dc6dcbb9c

@ -24,7 +24,7 @@ int main() {
int mx = 1; // 最起码a[i]==b[j],有一个数字是一样嘀~
// f[i-1]是肯定的了问题是b的前驱在哪里需要枚举1~j-1
for (int k = 1; k < j; k++)
if (b[j] > b[k]) // j可以接在k后面那么可能的最大值为f[i-1][k]+1
if (a[i] > b[k]) // j可以接在k后面那么可能的最大值为f[i-1][k]+1
mx = max(mx, f[i - 1][k] + 1);
// 更新答案
f[i][j] = max(f[i][j], mx);

@ -7,6 +7,7 @@ int f[N][N];
int res;
// O(n^2)
// f[i][j]—集合:考虑 a 中前 i 个数字b 中前 j 个数字 ,且当前以 b[j] 结尾的子序列的方案
int main() {
int n;
cin >> n;
@ -14,10 +15,9 @@ int main() {
for (int i = 1; i <= n; i++) cin >> b[i];
for (int i = 1; i <= n; i++) {
int mx = 1; // 将mx提到二层循环的外面因为O(n^3)之所以慢就是因为存在重复计算每次都需要从头找一遍可以接在后面的同时上升序列最长的那个k
// 由于循环从左到右进行时每次这个mx是可以记录下来下次不用重复计算的所以可以复用
int mx = 1; // 如果a[i]==b[j],那么LICS最小是1.如果下面的循环中没有一个if被执行则mx没使上
for (int j = 1; j <= n; j++) {
f[i][j] = f[i - 1][j];
f[i][j] = f[i - 1][j]; // 先继承过来现实含义即使a[i]!=b[j],那么最长长度不会因为i的增加而变化即f[i][j]=f[i-1][j]
if (a[i] == b[j]) f[i][j] = mx;
if (a[i] > b[j]) mx = max(mx, f[i - 1][j] + 1);
}

@ -597,7 +597,7 @@ int main() {
int mx = 1; // 最起码a[i]==b[j],有一个数字是一样嘀~
// f[i-1]是肯定的了问题是b的前驱在哪里需要枚举1~j-1
for (int k = 1; k < j; k++)
if (b[j] > b[k]) // j可以接在k后面那么可能的最大值为f[i-1][k]+1
if (a[i] > b[k]) // j可以接在k后面那么可能的最大值为f[i-1][k]+1
mx = max(mx, f[i - 1][k] + 1);
// 更新答案
f[i][j] = max(f[i][j], mx);
@ -610,8 +610,12 @@ int main() {
return 0;
}
```
前面之所以把$b[j]$换成$a[i]$,是因为方便现在考虑。
由于在枚举计算$f[i][j]$时,却用到的是和内层循环(即$b[j]$)无关的,只和外层循环(即$a[i]$)有关,而我们在计算$f[i][j]$,每次都要用到前$j1$个数中小于$a[i]$的$f[i-1][k]$最大值,所以我们可以用一个变量$mx$不断更新它来保存前$j1$的答案,就可以避免重复计算,从而降低时间复杂度。
$O(N^2)$
```cpp {.line-numbers}
#include <bits/stdc++.h>
@ -622,6 +626,7 @@ int f[N][N];
int res;
// O(n^2)
// f[i][j]—集合:考虑 a 中前 i 个数字b 中前 j 个数字 ,且当前以 b[j] 结尾的子序列的方案
int main() {
int n;
cin >> n;
@ -629,10 +634,9 @@ int main() {
for (int i = 1; i <= n; i++) cin >> b[i];
for (int i = 1; i <= n; i++) {
int mx = 1; // 将mx提到二层循环的外面因为O(n^3)之所以慢就是因为存在重复计算每次都需要从头找一遍可以接在后面的同时上升序列最长的那个k
// 由于循环从左到右进行时每次这个mx是可以记录下来下次不用重复计算的所以可以复用
int mx = 1; // 如果a[i]==b[j],那么LICS最小是1.如果下面的循环中没有一个if被执行则mx没使上
for (int j = 1; j <= n; j++) {
f[i][j] = f[i - 1][j];
f[i][j] = f[i - 1][j]; // 先继承过来现实含义即使a[i]!=b[j],那么最长长度不会因为i的增加而变化即f[i][j]=f[i-1][j]
if (a[i] == b[j]) f[i][j] = mx;
if (a[i] > b[j]) mx = max(mx, f[i - 1][j] + 1);
}
@ -643,6 +647,5 @@ int main() {
return 0;
}
```
[最长上升子序列 ($LIS$) 详解+例题模板 (全)](https://blog.csdn.net/lxt_Lucia/article/details/81206439)

Loading…
Cancel
Save