定义
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示
s
1
s1
s1 的前
i
i
i 个字符和
s
2
s2
s2 的前
j
j
j 个字符的最长公共子序列长度
如果
s
1
[
i
−
1
]
=
=
s
2
[
j
−
1
]
s1[i-1] == s2[j-1]
s1[i−1]==s2[j−1],则
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
1
]
+
1
dp[i][j] = dp[i-1][j-1] + 1
dp[i][j]=dp[i−1][j−1]+1
如果
s
1
[
i
−
1
]
!
=
s
2
[
j
−
1
]
s1[i-1] != s2[j-1]
s1[i−1]!=s2[j−1],则
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
)
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
dp[i][j]=max(dp[i−1][j],dp[i][j−1])
最终答案为
d
p
[
n
]
[
m
]
dp[n][m]
dp[n][m]
代码
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
string s1, s2;
cin >> s1 >> s2;
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(s1[i-1] == s2[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1;
} else {
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
}
cout << dp[n][m] << endl;
return 0;
}
importjava.util.*;publicclassMain{publicstaticvoidmain(String[] args){Scanner sc =newScanner(System.in);int n = sc.nextInt();int m = sc.nextInt();String s1 = sc.next();String s2 = sc.next();int[][] dp =newint[n +1][m +1];for(int i =1; i <= n; i++){for(int j =1; j <= m; j++){if(s1.charAt(i-1)== s2.charAt(j-1)){
dp[i][j]= dp[i-1][j-1]+1;}else{
dp[i][j]=Math.max(dp[i-1][j], dp[i][j-1]);}}}System.out.println(dp[n][m]);}}
n, m =map(int,input().split())
s1 =input()
s2 =input()
dp =[[0]*(m +1)for _ inrange(n +1)]for i inrange(1, n +1):for j inrange(1, m +1):if s1[i-1]== s2[j-1]:
dp[i][j]= dp[i-1][j-1]+1else:
dp[i][j]=max(dp[i-1][j], dp[i][j-1])print(dp[n][m])
算法及复杂度
算法:动态规划
时间复杂度:
O
(
m
n
)
\mathcal{O}(mn)
O(mn) - 两层嵌套循环遍历
空间复杂度:
O
(
m
n
)
\mathcal{O}(mn)
O(mn) - 需要一个
m
×
n
m×n
m×n 的
d
p
dp
dp 数组
[题目链接](https://www.nowcoder.com/practice/5f65ccbb025240bd8458eb6479c2612e?tpId=308&tqId=2357994&sourceUrl=/exam/oj&channelPut=wcsdn&fromPut=wcsdn)
## 解题思路
这是一个经典的动态规划问题。我们可以用以下思路解决:
1. 定义 $dp[i]$ 表示以第i个数字结尾的最长上升子序列的长度
2. 对于每个位置 $i$,遍历它前面的所有位置 $j$
3. 如果 $arr[i] > arr[j]$,说明可以将 $arr[i]$ 接在以 $arr[j]$ 结尾的上升子序列后面
4. 状态转移方程:$dp[i] = max(dp[j] + 1)$ 其中 $j < i$ 且 $arr[j] < arr[i]$
5. 最终答案为 $dp$ 数组中的最大值
---
## 代码
```c++ []
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> arr(n);
for(int i = 0; i < n; i++) {
cin >> arr[i];
}
vector<int> dp(n, 1); // 初始化dp数组,每个元素至少是长度为1的子序列
int maxLen = 1;
for(int i = 1; i < n; i++) {
for(int j = 0; j < i; j++) {
if(arr[i] > arr[j]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
maxLen = max(maxLen, dp[i]);
}
cout << maxLen << endl;
return 0;
}
```
```java []
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int[] dp = new int[n];
Arrays.fill(dp, 1); // 初始化dp数组
int maxLen = 1;
for(int i = 1; i < n; i++) {
for(int j = 0; j < i; j++) {
if(arr[i] > arr[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
maxLen = Math.max(maxLen, dp[i]);
}
System.out.println(maxLen);
}
}
```
```python []
n = int(input())
arr = list(map(int, input().split()))
dp = [1] * n # 初始化dp数组
for i in range(1, n):
for j in range(i):
if arr[i] > arr[j]:
dp[i] = max(dp[i], dp[j] + 1)
print(max(dp))
```
---
## 算法及复杂度
- 算法:动态规划
- 时间复杂度:$\mathcal{O}(n^2)$ - 两层嵌套循环
- 空间复杂度:$\mathcal{O}(n)$ - 需要一个长度为 $n$ 的 $dp$ 数组
````