【常见面试算法】最长公共子序列
给定两个长度分别为N和M的字符串A和B,求既是A的子序列又是B的子序列的字符串长度最长是多少。
输入格式
第一行包含两个整数N和M。
第二行包含一个长度为N的字符串,表示字符串A。
第三行包含一个长度为M的字符串,表示字符串B。
字符串均由小写字母构成。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤10001≤N≤1000,
输入样例:
4 5 acbd abedc
输出样例:
3
解答:
import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); in.nextLine(); char[] s1 = in.nextLine().toCharArray(); char[] s2 = in.nextLine().toCharArray(); //dp[i][j]的含义是:s1[0-i]和s2[0-j]的最长公共子序列 int[][] dp = new int[n][m]; //初始化,两个字符串的第一个字符是否相等 dp[0][0] = s1[0] == s2[0] ? 1 : 0; //初始化,把第一行和第一列进行初始化,由于判断的是子序列,所以 //只要有一个字符相等,后面的dp就都是1 for (int i = 1; i < n; i++) { dp[i][0] = Math.max(dp[i - 1][0], s1[i] == s2[0] ? 1 : 0); } for (int i = 1; i < m; i++) { dp[0][i] = Math.max(dp[0][i - 1], s1[0] == s2[i] ? 1 : 0); } for (int i = 1; i < n; i++) { for (int j = 1; j < m; j++) { //默认情况,dp[i][j]应该是将s1或者s2去掉一个字符后的dp的较大值 dp[i][j] = Math.max(dp[i][j - 1],dp[i - 1][j]); //若s1[i]==s2[j],还需要判断和dp[i - 1][j - 1] + 1比较后的较大值 if (s1[i] == s2[j]) { dp[i][j] = Math.max(dp[i][j],dp[i - 1][j - 1] + 1); } } } System.out.println(dp[n - 1][m - 1]); } }