modify code

master
algorithmzuo 3 years ago
parent ac9c3d6b0f
commit e50de1cee5

@ -14,24 +14,92 @@ public class Code04_LongestCommonSubsequence {
return process1(str1, str2, str1.length - 1, str2.length - 1); return process1(str1, str2, str1.length - 1, str2.length - 1);
} }
// str1[0...i]和str2[0...j],这个范围上最长公共子序列长度是多少?
// 可能性分类:
// a) 最长公共子序列既不以str1[i]字符结尾、也不以str2[j]字符结尾
// 比如: str1[0..5] = "1a234b", str2[0..7] = "cd12e34f"
// 其中最长公共子序列为"1234"
// 可以看到这个最长公共子序列根本和str1[i]字符、str2[j]字符没有任何关系
// a)的可能性下,最长公共子序列总长度 =
// str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归)
// ======================================================
// b) 最长公共子序列以str1[i]字符结尾、不以str2[j]字符结尾
// 比如: str1[0..5] = "1a23b4", str2[0..7] = "cd12e34f"
// 其中最长公共子序列为"1234"
// 可以看到这个最长公共子序列以str1[i]字符结尾但是不以str2[j]字符结尾
// b)的可能性下,最长公共子序列总长度 =
// str1[0...i]与str2[0...j-1]的最长公共子序列长度(后续递归)
// ======================================================
// c) 最长公共子序列不以str1[i]字符结尾、以str2[j]字符结尾
// 比如: str1[0..5] = "1a234b", str2[0..7] = "cd12e3f4"
// 其中最长公共子序列为"1234"
// 可以看到这个最长公共子序列不以str1[i]字符结尾以str2[j]字符结尾
// c)的可能性下,最长公共子序列总长度 =
// str1[0...i-1]与str2[0...j]的最长公共子序列长度(后续递归)
// ======================================================
// d) 最长公共子序列同时以str1[i]字符和str2[j]字符结尾
// 比如: str1[0..5] = "1a23b4", str2[0..7] = "cd12ef34"
// 其中最长公共子序列为"1234"
// 可以看到这个公共子序列的结尾是'4'同时以str1[5]字符和str2[7]字符结尾
// 同时可以看到可能性d)存在的条件一定是在str1[i] == str2[j]的情况下,才成立的
// d)的可能性下,最长公共子序列总长度 =
// str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归) + 1(共同的结尾)
// ======================================================
// 综上,四种情况已经穷尽了所有可能性。四种情况中取最大即可
// 其中b)、c)一定参与最大值的比较,
// 当str1[i] == str2[j]时a)一定比d)小所以d)参与
// 当str1[i] != str2[j]时d)压根不存在所以a)参与
// 但是再次注意了!
// a)是str1[0...i-1]与str2[0...j-1]的最长公共子序列长度
// b)是str1[0...i]与str2[0...j-1]的最长公共子序列长度
// c)是str1[0...i-1]与str2[0...j]的最长公共子序列长度
// a)中str1的范围 < b)中str1的范围a)中str2的范围 == b)中str2的范围
// 所以a)不用求也知道它比不过b)啊因为有一个样本的范围比b)小啊!
// a)中str1的范围 == c)中str1的范围a)中str2的范围 < c)中str2的范围
// 所以a)不用求也知道它比不过c)啊因为有一个样本的范围比c)小啊!
// 至此可以知道a)就是个垃圾,有它没它,都不影响最大值的决策
// 所以当str1[i] == str2[j]时b)、c)、d)中选出最大值
// 当str1[i] != str2[j]时b)、c)中选出最大值
public static int process1(char[] str1, char[] str2, int i, int j) { public static int process1(char[] str1, char[] str2, int i, int j) {
if (i == 0 && j == 0) { if (i == 0 && j == 0) {
// str1[0..0]和str2[0..0],都只剩一个字符了
// 那如果字符相等公共子序列长度就是1不相等就是0
// 这显而易见
return str1[i] == str2[j] ? 1 : 0; return str1[i] == str2[j] ? 1 : 0;
} else if (i == 0) { } else if (i == 0) {
// 这里的情况为:
// str1[0...0]和str2[0...j]str1只剩1个字符了但是str2不只一个字符
// 因为str1只剩一个字符了所以str1[0...0]和str2[0...j]公共子序列最多长度为1
// 如果str1[0] == str2[j]那么此时相等已经找到了公共子序列长度就是1也不可能更大了
// 如果str1[0] != str2[j],只是此时不相等而已,
// 那么str2[0...j-1]上有没有字符等于str1[0]呢?不知道,所以递归继续找
if (str1[i] == str2[j]) { if (str1[i] == str2[j]) {
return 1; return 1;
} else { } else {
return process1(str1, str2, i, j - 1); return process1(str1, str2, i, j - 1);
} }
} else if (j == 0) { } else if (j == 0) {
// 和上面的else if同理
// str1[0...i]和str2[0...0]str2只剩1个字符了但是str1不只一个字符
// 因为str2只剩一个字符了所以str1[0...i]和str2[0...0]公共子序列最多长度为1
// 如果str1[i] == str2[0]那么此时相等已经找到了公共子序列长度就是1也不可能更大了
// 如果str1[i] != str2[0],只是此时不相等而已,
// 那么str1[0...i-1]上有没有字符等于str2[0]呢?不知道,所以递归继续找
if (str1[i] == str2[j]) { if (str1[i] == str2[j]) {
return 1; return 1;
} else { } else {
return process1(str1, str2, i - 1, j); return process1(str1, str2, i - 1, j);
} }
} else { // i != 0 && j != 0 } else { // i != 0 && j != 0
// 这里的情况为:
// str1[0...i]和str2[0...i]str1和str2都不只一个字符
// 看函数开始之前的注释部分
// p1就是可能性c)
int p1 = process1(str1, str2, i - 1, j); int p1 = process1(str1, str2, i - 1, j);
// p2就是可能性b)
int p2 = process1(str1, str2, i, j - 1); int p2 = process1(str1, str2, i, j - 1);
// p3就是可能性d)如果可能性d)存在即str1[i] == str2[j]那么p3就求出来参与pk
// 如果可能性d)不存在即str1[i] != str2[j]那么让p3等于0然后去参与pk反正不影响
int p3 = str1[i] == str2[j] ? (1 + process1(str1, str2, i - 1, j - 1)) : 0; int p3 = str1[i] == str2[j] ? (1 + process1(str1, str2, i - 1, j - 1)) : 0;
return Math.max(p1, Math.max(p2, p3)); return Math.max(p1, Math.max(p2, p3));
} }

Loading…
Cancel
Save