《程式設計師程式碼面試指南》求兩個字串最長公共子串
阿新 • • 發佈:2018-12-11
/** * 題目: * 給定兩個字串 str1 和 str2,返回兩個字串的最長公共子串。 *舉例: * str1 = "1AB2345CD",str2 = "12345EF",返回"2345"。 */ /** * 解答: * 經典動態規劃的方法可以做到時間複雜度為O(M*N),額外空間複雜度為O(M*N)。 * 首先需要生成動態規劃表。生成大小為M*N的矩陣dp,行數為M,列數為N。dp[i][j]的含義是: * 在必須把str1[i]和str2[j]當作公共子串最後一個字元的情況下,最長公共子串能有多長。 * 比如,str1 = "A1234B",str2 = "CD1234",dp[3][4]的含義是在必須把str1[3]和str2[4]當作公共子串 * 最長能有多長。這時候最長公共子串為"123"所以dp[3][4]為3。 * 再如,str1 = "A12E4B",str2 = "CD12F4",dp[3][4]的含義是必須把str1[3]和str2[4]當作公共子串的最後一個 * 字元的情況下,公共子串能有多長。顯然這種情況不可能構成公共子串。dp[3][4]為0。 */ /** * 1.矩陣dp第一列即dp[0..M-1][0]。對某一個位置(i,0)來說,如果str[i] == str2[0],令dp[i][0] = 1, * 否則令dp[i][0] = 0。 * 比如str1 = "ABAC" str2 = "A"。dp矩陣第一列上的值依次為dp[0][0] = 1,dp[2][0] = 0,dp[3][0] = 1, * dp[3][0] = 0。 * 2.矩陣dp第一行dp[0][0...N-1]與步驟1同理。對某一個位置(0,j)來說,如果str1[0] == str2[j],令 * dp[0][j] = 1,否則令dp[0][j] = 0。 * 3.其他位置按照從左到右,再從上到下來計算,dp[i][j]的值只能有兩種情況。 * 3.1如果str1[i] != str2[j]說明在必須把str1[i]和str2[j]作為公共子串的最後一個字元是不可能的,令 * dp[i][j] = 0。 * 3.2如果str1[i] == str[j]說明str1[i]和str2[j]可以作為公共子串最後一個字元,從最後一個字元能向 * 左擴多大的長度呢?就是dp[i-1][j-1]的值,所以令dp[i][j] = dp[i-1][j-1]+1。 */ /** * 生成動態規劃表之後,得到最長公共子串是非常容易的。 */
/** * 題目: * 給定兩個字串 str1 和 str2,返回兩個字串的最長公共子串。 *舉例: * str1 = "1AB2345CD",str2 = "12345EF",返回"2345"。 */ /** * 解答: * 經典動態規劃的方法可以做到時間複雜度為O(M*N),額外空間複雜度為O(M*N)。 * 首先需要生成動態規劃表。生成大小為M*N的矩陣dp,行數為M,列數為N。dp[i][j]的含義是: * 在必須把str1[i]和str2[j]當作公共子串最後一個字元的情況下,最長公共子串能有多長。 * 比如,str1 = "A1234B",str2 = "CD1234",dp[3][4]的含義是在必須把str1[3]和str2[4]當作公共子串 * 最長能有多長。這時候最長公共子串為"123"所以dp[3][4]為3。 * 再如,str1 = "A12E4B",str2 = "CD12F4",dp[3][4]的含義是必須把str1[3]和str2[4]當作公共子串的最後一個 * 字元的情況下,公共子串能有多長。顯然這種情況不可能構成公共子串。dp[3][4]為0。 */ /** * 1.矩陣dp第一列即dp[0..M-1][0]。對某一個位置(i,0)來說,如果str[i] == str2[0],令dp[i][0] = 1, * 否則令dp[i][0] = 0。 * 比如str1 = "ABAC" str2 = "A"。dp矩陣第一列上的值依次為dp[0][0] = 1,dp[2][0] = 0,dp[3][0] = 1, * dp[3][0] = 0。 * 2.矩陣dp第一行dp[0][0...N-1]與步驟1同理。對某一個位置(0,j)來說,如果str1[0] == str2[j],令 * dp[0][j] = 1,否則令dp[0][j] = 0。 * 3.其他位置按照從左到右,再從上到下來計算,dp[i][j]的值只能有兩種情況。 * 3.1如果str1[i] != str2[j]說明在必須把str1[i]和str2[j]作為公共子串的最後一個字元是不可能的,令 * dp[i][j] = 0。 * 3.2如果str1[i] == str[j]說明str1[i]和str2[j]可以作為公共子串最後一個字元,從最後一個字元能向 * 左擴多大的長度呢?就是dp[i-1][j-1]的值,所以令dp[i][j] = dp[i-1][j-1]+1。 */ /** * 生成動態規劃表之後,得到最長公共子串是非常容易的。 */ public class LongestPublicCharacterString { public static int[][] getdp(char[] str1, char[] str2){ int[][] dp = new int[str1.length][str2.length]; for(int i = 0; i < str1.length; i++){ if(str1[i] == str2[0]){ dp[i][0] = 1; } } for(int j = 0; j < str2.length; j++){ if(str2[j] == str1[0]){ dp[0][j] = 1; } } for(int i = 1; i < str1.length; i++){ for(int j = 1; j < str2.length; j++){ if(str1[i] == str2[j]){ dp[i][j] = dp[i-1][j-1] + 1; } } } return dp; } public static String lcst1(String str1, String str2){ if(str1 == null || str2 == null || str1.equals("") || str2.equals("")){ return ""; } char[] chs1 = str1.toCharArray(); char[] chs2 = str2.toCharArray(); int[][] dp = getdp(chs1,chs2); int end = 0; int max = 0; for(int i = 0; i < chs1.length; i++){ for(int j = 0; j < chs2.length; j++){ if(dp[i][j] > max){ end = i; max = dp[i][j]; } } } return str1.substring(end - max + 1, end + 1); } public static void main(String[] args) { String str1 = "abcbcbbc"; String str2 = "cbcbaaa"; System.out.println(lcst1(str1, str2)); } }
參考資料:《程式設計師面試程式碼指南》左程雲 著