文章目录
- 例题列表
- 898. 数字三角形
- 895. 最长上升子序列(n^2两重循环dp)
- 896. 最长上升子序列 II(贪心+二分查找)
- 897. 最长公共子序列
- 902. 最短编辑距离
- 899. 编辑距离⭐⭐⭐⭐⭐
例题列表
898. 数字三角形
每个数字可以从它上面的左右两边选择一个大的转移过来。
如果想不清楚的话,可以不要节省空间,就写个完整的 n * n 大小的 dp 数组就好。
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] dp = new int[n][n];
dp[0][0] = sc.nextInt();
for (int i = 1; i < n; ++i) {
for (int j = 0; j <= i; ++j) {
dp[i][j] = sc.nextInt();
if (j == 0) dp[i][j] += dp[i - 1][j];
else if (j == i) dp[i][j] += dp[i - 1][j - 1];
else dp[i][j] += Math.max(dp[i - 1][j - 1], dp[i - 1][j]);
}
}
System.out.println(Arrays.stream(dp[n - 1]).max().getAsInt());
}
}
895. 最长上升子序列(n^2两重循环dp)
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
int[] dp = new int[n];
Arrays.fill(dp, 1);
for (int i = 0; i < n; ++i) {
a[i] = sc.nextInt();
for (int j = 0; j < i; ++j) {
if (a[i] > a[j]) dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
System.out.println(Arrays.stream(dp).max().getAsInt());
}
}
896. 最长上升子序列 II(贪心+二分查找)
https://www.acwing.com/problem/content/898/
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
List<Integer> ls = new ArrayList<>();
for (int i = 0; i < n; ++i) {
int a = sc.nextInt();
if (ls.isEmpty() || a > ls.get(ls.size() - 1)) ls.add(a);
else {
// 找到列表第一个>=当前元素的值
int l = 0, r = ls.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (ls.get(mid) < a) l = mid + 1;
else r = mid;
}
ls.set(l, a);
}
}
System.out.println(ls.size());
}
}
897. 最长公共子序列
https://www.acwing.com/problem/content/899/
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
char[] a = sc.next().toCharArray(), b = sc.next().toCharArray();
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[i - 1] == b[j - 1]) {
dp[i][j] = Math.max(1 + dp[i - 1][j - 1], dp[i][j]);
} else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
System.out.println(dp[n][m]);
}
}
902. 最短编辑距离
https://www.acwing.com/problem/content/904/
三种编辑方式,对应着从 dp[i - 1][j - 1]
、dp[i][j - 1]
、dp[i - 1][j]
转移过来。
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
char[] a = sc.next().toCharArray();
int m = sc.nextInt();
char[] b = sc.next().toCharArray();
int[][] dp = new int[n + 1][m + 1];
for (int i = 0; i <= n; ++i) {
Arrays.fill(dp[i], Integer.MAX_VALUE);
dp[i][0] = i;
}
for (int j = 0; j <= m; ++j) dp[0][j] = j;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[i - 1] == b[j - 1]) {
dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i][j]);
} else dp[i][j] = 1 + Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
}
}
System.out.println(dp[n][m]);
}
}
899. 编辑距离⭐⭐⭐⭐⭐
https://www.acwing.com/problem/content/901/
不要被吓到,算一下时间复杂度:1000 * 1000 * 10 * 10 = 10^8
所以就是上一题编辑距离的简单应用。
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
String[] strs = new String[n];
for (int i = 0; i < n; ++i) {
strs[i] = sc.next();
}
for (int i = 0; i < m; ++i) {
String s = sc.next();
int k = sc.nextInt(), res = 0;
for (int j = 0; j < n; ++j) {
if (edit(strs[j], s) <= k) ++res;
}
System.out.println(res);
}
}
static int edit(String a, String b) {
int m = a.length(), n = b.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i <= m; ++i) dp[i][0] = i;
for (int j = 0; j <= n; ++j) dp[0][j] = j;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (a.charAt(i - 1) != b.charAt(j - 1)) dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
else dp[i][j] = dp[i - 1][j - 1];
}
}
return dp[m][n];
}
}