还是dp问题,但这次更多的是线性,也就是有点像怎么走字符串最优问题。
一.数字三角形
1.题目
2. 代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[][] roads = new int[n + 10][n + 10];
for(int i = 1;i <= n; i ++) {
for(int j = 1;j <= i; j++) {
roads[i][j] = in.nextInt();
}
}
int[][] f = new int[n + 10][n + 10];
int ans = 0;
for(int i = n;i >= 1;i --) {
for(int j = 1; j <= i; j++) {
f[i][j] = Math.max(f[i + 1][j], f[i + 1][j + 1]) + roads[i][j];
}
}
System.out.println(f[1][1]); // 一开始输出有问题,应该从起点出发就知道最长的路径
}
}
3.想法
因为我一开始就是想着逆序去求解f数组,所以没有边界问题,如果是正序去处理f数组的话,会有边界问题,需要注意
最长上升子序列
1. 题目
2. 代码
第一种解法:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] a = new int[n + 1];
for (int i = 1;i <= n;i ++) {
a[i] = in.nextInt();
}
int[] f = new int[n + 1];
int ans = 0;
for (int i = 1;i <= n;i ++) {
f[i] = 1;
for(int j = 1; j < i;j ++) { // 从小到大,能保证每个f里面存的数值都是严格单调递增的
if (a[j] < a[i]) {
f[i] = Math.max(f[i], f[j] + 1);
}
}
ans = Math.max(ans, f[i]);
}
System.out.println(ans);
}
}
第二种解法:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] a = new int[n + 1];
for (int i = 1;i <= n;i ++) {
a[i] = in.nextInt();
}
int len = 1;
int[] nums = new int[n + 10];
for (int i = 1; i <= n;i ++) {
int l = 1, r = len;
while (l < r) {
int mid = l + r + 1 >> 1;
if (nums[mid] < a[i]) l = mid;
else r = mid - 1;
}
len = Math.max(len, r + 1);
nums[r + 1] = a[i];
}
System.out.println(len - 1);
}
}
3. 想法
如果可能的话,最好掌握第二种解法,又或者说一切搜索查询问题,只要有序,都可以思路往二分查找去思考
最长公共子序列
1. 题目
2. 代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
String a = in.next();
char[] aa = new char[n + 1];
for (int i = 1;i <= n;i ++) {
aa[i] = a.charAt(i - 1);
}
String b = in.next();
char[] bb = new char[m + 1];
for (int i = 1;i <= m;i ++) {
bb[i] = b.charAt(i - 1);
}
int[][] f = new int[n + 1][m + 1];
for (int i = 1;i <= n;i ++) {
for (int j = 1;j <= m;j ++) {
// f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]) + 1;
if (aa[i] == bb[j]) {
f[i][j] = Math.max(f[i][j], f[i - 1][j - 1] + 1);
} else {
f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]);
}
}
}
System.out.println(f[n][m]);
}
}
3. 想法
最短编辑距离
1. 题目
2. 代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String a = in.next();
char[] aa = new char[n + 1];
for (int i = 1;i <= n; i++) {
aa[i] = a.charAt(i - 1);
}
int m = in.nextInt();
String b = in.next();
char[] bb = new char[m + 1];
for (int i = 1;i <= m; i++) {
bb[i] = b.charAt(i - 1);
}
int[][] f = new int[n + 10][m + 10];
for (int i = 1;i <= n;i ++) {
for (int j = 1;j <= m;j ++) {
f[i][j] = Math.min(f[i - 1][j], f[i][j - 1]) + 1;
if (aa[i] == bb[j]) {
f[i][j] = Math.min(f[i][j], f[i - 1][j - 1]);
} else {
f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + 1);
}
}
}
System.out.println(f[n][m]);
}
}