Java-LeetCode1143. 最长公共子序列-动态规划&回溯法
最长公共子序列
http://www.nowcoder.com/questionTerminal/6d29638c85bb4ffd80c020fe244baf11
LeetCode原题
- 算法
- 1.动态规划:dp[i][j]表示str1[0,i-1]和str2[0,j-1]的最长公共子序列
- 2.初始状态:dp[x][0] = 0, dp[0][x] = 0
- 3.过渡公式:
- 如果str1[i]==str2[j], dp[i][j] = dp[i-1][j-1] + 1;
- 如果str1[i]!=str2[j], dp[i][j] = MAX(dp[i-1][j], dp[i][j-1]);
public int longestCommonSubsequence(String text1, String text2) { int[][] dp = new int[text1.length()+1][text2.length()+1]; for (int i = 1; i <= text1.length(); i++) { for (int j = 1; j <= text2.length(); j++) { if (text1.charAt(i-1) == text2.charAt(j-1)) { dp[i][j] = dp[i-1][j-1] + 1; } else { dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); } } } return dp[text1.length()][text2.length()]; }
- 算法
- 1.空间优化
- 2.考虑每轮外层循环更新dp数组需要那些值来使用辅助变量
public int longestCommonSubsequence(String text1, String text2) { int[] dp = new int[text2.length()+1]; for (int i = 1; i <= text1.length(); i++) { int prev = dp[0], curr = dp[1]; for (int j = 1; j <= text2.length(); j++) { if (text1.charAt(i-1) == text2.charAt(j-1)) { dp[j] = prev + 1; } else { dp[j] = Math.max(curr, dp[j-1]); } if (j < text2.length()) { prev = curr; curr = dp[j+1]; } } } return dp[text2.length()]; }
牛客本题
- 算法
- 1.动态规划的过程中保存结果:伴随dp数组的StringDp数组跟随变化
- 2.避免内存超限,这里使用优化后的空间复杂度来计算
public String LCS(String text1, String text2) { String[] stringDp = new String[text2.length()+1]; for (int i = 0; i < stringDp.length; i++) { stringDp[i] = new String(); } int[] dp = new int[text2.length()+1]; for (int i = 1; i <= text1.length(); i++) { int prev = dp[0], curr = dp[1]; String stringPrev = stringDp[0], stringCurr = stringDp[1]; for (int j = 1; j <= text2.length(); j++) { if (text1.charAt(i-1) == text2.charAt(j-1)) { dp[j] = prev + 1; stringDp[j] = stringPrev + text2.substring(j-1, j); } else { dp[j] = Math.max(curr, dp[j-1]); if (curr > dp[j-1]) { dp[j] = curr; stringDp[j] = stringCurr; } else { dp[j] = dp[j-1]; stringDp[j] = stringDp[j-1]; } } if (j < text2.length()) { prev = curr; curr = dp[j+1]; stringPrev = stringCurr; stringCurr = stringDp[j+1]; } } } return stringDp[text2.length()]; }
- 算法
- 动态规划后根据dp数组回溯结果
public String LCS(String text1, String text2) { int length1 = text1.length(), length2 = text2.length(); int[][] dp = new int[length1+1][length2+1]; for (int i = 1; i <= text1.length(); i++) { for (int j = 1; j <= text2.length(); j++) { if (text1.charAt(i-1) == text2.charAt(j-1)) { dp[i][j] = dp[i-1][j-1] + 1; } else { dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); } } } StringBuilder result = new StringBuilder(); int i = length1, j = length2; while (i > 0 && j > 0) { if (text1.charAt(i-1) == text2.charAt(j-1)) { result.append(text1.charAt(i-1)); i--; j--; } else { if (dp[i][j-1] > dp[i-1][j]) { j--; } else { i--; } } } return result.reverse().toString(); }