@@ -14,24 +14,92 @@ public static int longestCommonSubsequence1(String s1, String s2) {
1414return process1 (str1 , str2 , str1 .length - 1 , str2 .length - 1 );
1515}
1616
17+ // str1[0...i]和str2[0...j],这个范围上最长公共子序列长度是多少?
18+ // 可能性分类:
19+ // a) 最长公共子序列,既不以str1[i]字符结尾、也不以str2[j]字符结尾
20+ // 比如: str1[0..5] = "1a234b", str2[0..7] = "cd12e34f"
21+ // 其中最长公共子序列为"1234"
22+ // 可以看到,这个最长公共子序列根本和str1[i]字符、str2[j]字符没有任何关系
23+ // a)的可能性下,最长公共子序列总长度 =
24+ // str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归)
25+ // ======================================================
26+ // b) 最长公共子序列,以str1[i]字符结尾、不以str2[j]字符结尾
27+ // 比如: str1[0..5] = "1a23b4", str2[0..7] = "cd12e34f"
28+ // 其中最长公共子序列为"1234"
29+ // 可以看到,这个最长公共子序列以str1[i]字符结尾,但是不以str2[j]字符结尾
30+ // b)的可能性下,最长公共子序列总长度 =
31+ // str1[0...i]与str2[0...j-1]的最长公共子序列长度(后续递归)
32+ // ======================================================
33+ // c) 最长公共子序列,不以str1[i]字符结尾、以str2[j]字符结尾
34+ // 比如: str1[0..5] = "1a234b", str2[0..7] = "cd12e3f4"
35+ // 其中最长公共子序列为"1234"
36+ // 可以看到,这个最长公共子序列不以str1[i]字符结尾,以str2[j]字符结尾
37+ // c)的可能性下,最长公共子序列总长度 =
38+ // str1[0...i-1]与str2[0...j]的最长公共子序列长度(后续递归)
39+ // ======================================================
40+ // d) 最长公共子序列,同时以str1[i]字符和str2[j]字符结尾
41+ // 比如: str1[0..5] = "1a23b4", str2[0..7] = "cd12ef34"
42+ // 其中最长公共子序列为"1234"
43+ // 可以看到这个公共子序列的结尾是'4',同时以str1[5]字符和str2[7]字符结尾
44+ // 同时可以看到,可能性d)存在的条件,一定是在str1[i] == str2[j]的情况下,才成立的
45+ // d)的可能性下,最长公共子序列总长度 =
46+ // str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归) + 1(共同的结尾)
47+ // ======================================================
48+ // 综上,四种情况已经穷尽了所有可能性。四种情况中取最大即可
49+ // 其中b)、c)一定参与最大值的比较,
50+ // 当str1[i] == str2[j]时,a)一定比d)小,所以d)参与
51+ // 当str1[i] != str2[j]时,d)压根不存在,所以a)参与
52+ // 但是再次注意了!
53+ // a)是:str1[0...i-1]与str2[0...j-1]的最长公共子序列长度
54+ // b)是:str1[0...i]与str2[0...j-1]的最长公共子序列长度
55+ // c)是:str1[0...i-1]与str2[0...j]的最长公共子序列长度
56+ // a)中str1的范围 < b)中str1的范围,a)中str2的范围 == b)中str2的范围
57+ // 所以a)不用求也知道,它比不过b)啊,因为有一个样本的范围比b)小啊!
58+ // a)中str1的范围 == c)中str1的范围,a)中str2的范围 < c)中str2的范围
59+ // 所以a)不用求也知道,它比不过c)啊,因为有一个样本的范围比c)小啊!
60+ // 至此,可以知道,a)就是个垃圾,有它没它,都不影响最大值的决策
61+ // 所以,当str1[i] == str2[j]时,b)、c)、d)中选出最大值
62+ // 当str1[i] != str2[j]时,b)、c)中选出最大值
1763public static int process1 (char [] str1 , char [] str2 , int i , int j ) {
1864if (i == 0 && j == 0 ) {
65+ // str1[0..0]和str2[0..0],都只剩一个字符了
66+ // 那如果字符相等,公共子序列长度就是1,不相等就是0
67+ // 这显而易见
1968return str1 [i ] == str2 [j ] ? 1 : 0 ;
2069} else if (i == 0 ) {
70+ // 这里的情况为:
71+ // str1[0...0]和str2[0...j],str1只剩1个字符了,但是str2不只一个字符
72+ // 因为str1只剩一个字符了,所以str1[0...0]和str2[0...j]公共子序列最多长度为1
73+ // 如果str1[0] == str2[j],那么此时相等已经找到了!公共子序列长度就是1,也不可能更大了
74+ // 如果str1[0] != str2[j],只是此时不相等而已,
75+ // 那么str2[0...j-1]上有没有字符等于str1[0]呢?不知道,所以递归继续找
2176if (str1 [i ] == str2 [j ]) {
2277return 1 ;
2378} else {
2479return process1 (str1 , str2 , i , j - 1 );
2580}
2681} else if (j == 0 ) {
82+ // 和上面的else if同理
83+ // str1[0...i]和str2[0...0],str2只剩1个字符了,但是str1不只一个字符
84+ // 因为str2只剩一个字符了,所以str1[0...i]和str2[0...0]公共子序列最多长度为1
85+ // 如果str1[i] == str2[0],那么此时相等已经找到了!公共子序列长度就是1,也不可能更大了
86+ // 如果str1[i] != str2[0],只是此时不相等而已,
87+ // 那么str1[0...i-1]上有没有字符等于str2[0]呢?不知道,所以递归继续找
2788if (str1 [i ] == str2 [j ]) {
2889return 1 ;
2990} else {
3091return process1 (str1 , str2 , i - 1 , j );
3192}
3293} else { // i != 0 && j != 0
94+ // 这里的情况为:
95+ // str1[0...i]和str2[0...i],str1和str2都不只一个字符
96+ // 看函数开始之前的注释部分
97+ // p1就是可能性c)
3398int p1 = process1 (str1 , str2 , i - 1 , j );
99+ // p2就是可能性b)
34100int p2 = process1 (str1 , str2 , i , j - 1 );
101+ // p3就是可能性d),如果可能性d)存在,即str1[i] == str2[j],那么p3就求出来,参与pk
102+ // 如果可能性d)不存在,即str1[i] != str2[j],那么让p3等于0,然后去参与pk,反正不影响
35103int p3 = str1 [i ] == str2 [j ] ? (1 + process1 (str1 , str2 , i - 1 , j - 1 )) : 0 ;
36104return Math .max (p1 , Math .max (p2 , p3 ));
37105}
0 commit comments