动态规划:查找最长公共子序列

    xiaoxiao2022-07-07  145

    查找最长公共子序列

    什么是最长公共子序列?

    一个序列,如果是两个或多个已知序列的子序列,且是所有子序列中最长的,则为最长公共子序列。

    例: 如下有两个字符串: x:A B C B D A B y:B D C A B A 查找它们最长公共子序列。 则它们公共子序列有(B D A B)(B D A B) (B C B A)

    如何进行查找\思路?

    找最长公共子序列长度lcs(x,y) lcs(x[0],x[0])=0 lcs(x[1],x[1])=0 如果不相等为0 lcs(x[2],x[2])=0分情况: lcs(x[1],x[2])=0 lcs(x[2],x[1])=1 此时lcs(x[2],x[2])=1 即取两种情况的最大值 lcs(x[3],x[3])=2 lcs(x[4],x[4])=0分情况: lcs(x[3],x[4])=2 lcs(x[4],x[3])=2 此时lcs(x[4],x[4])=2 lcs(x[5],x[5])=0分情况: lcs(x[4],x[5)=3 lcs(x[5],x[4])=2 此时lcs(x[4],x[4])=3 。。。。。剩下的以此类推

    伪代码如下: lcs(x,y,i,j){ if(i0 or j0)return 0; else if(x[i]==x[j])return lcs(x,y,i,j)+1; else return max(lcs(x,y,i,j–),lcs(x,y,i-1,j)); }

    key1:穷举法

    穷举法需要遍历出所有的可能,在这不考虑。

    key2: 递归方法

    static int f(char[] a, char[] b, int i, int j) { if (i == 0 || j == 0) { return 0; } else if (a[i] == b[j]) { return f(a, b, i - 1, j - 1) + 1; } else { return Max(f(a, b, i, j - 1), f(a, b, i - 1, j)); } } static int Max(int a, int b) { if (a > b) return a; else return b; } public static void main(String[] args) { String s1 = " abcdfadskb"; String s2 = " abefaslf"; char[] c1 = new char[s1.length() + 1];// 带0号字符的新数组 char[] c2 = new char[s1.length() + 1];// 带0号字符的新数组 char[] t1 = s1.toCharArray(); char[] t2 = s1.toCharArray(); c1[0] = (char) 0; c2[0] = (char) 0; for (int i = 0; i < t1.length; i++) { c1[i + 1] = t1[i]; } for (int i = 0; i < t2.length; i++) { c2[i + 1] = t2[i]; } System.out.println(f(s1.toCharArray(), s2.toCharArray(), 4, 4)); }

    key3:备忘录法

    static int f(char[] a, char[] b, int i, int j, int[][] bak) { if (bak[i][j] != -1) return bak[i][j]; if (i == 0 || j == 0) { bak[i][j] = 0; } else if (a[i] == b[j]) { bak[i][j] = f(a, b, i - 1, j - 1, bak) + 1; } else { bak[i][j] = Max(f(a, b, i, j - 1, bak), f(a, b, i - 1, j, bak)); } return bak[i][j]; } static int Max(int a, int b) { if (a > b) return a; else return b; } public static void main(String[] args) { String s1 = " ABCBDAB"; String s2 = " BDCABA"; char[] c1 = new char[s1.length() + 1];// 带0号字符的新数组 char[] c2 = new char[s2.length() + 1];// 带0号字符的新数组 char[] t1 = s1.toCharArray(); char[] t2 = s1.toCharArray(); c1[0] = (char) 0;//前面扩张一个位置0 c2[0] = (char) 0; for (int i = 0; i < t1.length; i++) { c1[i + 1] = t1[i]; } for (int i = 0; i < t2.length; i++) { c2[i + 1] = t2[i]; } int[][] bak = new int[c1.length][c2.length]; for (int i = 0; i < c1.length; i++) { for (int j = 0; j < bak[i].length; j++) { bak[i][j] = -1; } } System.out.println(f(c1, c2, c1.length - 1, c2.length - 1, bak)); }

    key4:自底向上

    static int f(char[] a, char[] b, int i, int j, int[][] bak) { for(int ii=0;ii<=i;ii++) { for(int jj=0;jj<=j;jj++) { if (ii == 0 || jj == 0) { bak[ii][jj] = 0; } else if (a[ii] == b[jj]) { bak[ii][jj] = bak[ii-1][jj-1]+ 1; } else { bak[ii][jj] = Max(bak[ii-1][jj],bak[ii][jj-1]); } } } return bak[i][j]; } static int Max(int a, int b) { if (a > b) return a; else return b; } public static void main(String[] args) { String s1 = "ABCBDAB"; String s2 = "BDCABA"; // char[] c1 = new char[s1.length() + 1];// 带0号字符的新数组 char[] c1=new StringBuffer((char)0).append(s1).toString().toCharArray(); char[] c2 = new char[s2.length() + 1];// 带0号字符的新数组 // char[] t1 = s1.toCharArray(); char[] t2 = s2.toCharArray(); // c1[0] = (char) 0; c2[0] = (char) 0; // for (int i = 0; i < t1.length; i++) { // c1[i + 1] = t1[i]; // } for (int i = 0; i < t2.length; i++) { c2[i + 1] = t2[i]; } int[][] bak = new int[c1.length][c2.length]; System.out.println(f(c1, c2, c1.length - 1, c2.length - 1, bak)); }
    最新回复(0)