线性dp

53 阅读2分钟

还是dp问题,但这次更多的是线性,也就是有点像怎么走字符串最优问题。

一.数字三角形

1.题目

image.png

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. 题目

image.png

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. 题目

image.png

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. 想法

image.png

最短编辑距离

1. 题目

image.png

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]);

    }
}

3. 想法

image.png