Reprinted from http://blog.csdn.net/steven30832/article/details/8260189
A typical problem in dynamic planning is the longest public subsequence, but the subsequence here does not require continuity. If the sequence is required to be continuous, we call it a public substring, how can we get this string?
The simplest method is to compare in sequence, take a string as the parent string, then generate all the length substrings of the other string, and then compare and search in sequence from the parent string, here we can start with the longest substring to reduce the number of comparisons, but the complexity is still very high!
Then, let's take a look at this problem again. We create a comparison matrix to compare the two strings str1 and str2.
Defines LCS (I, j). When str1 [I] = str2 [J], LCS (I, j) = 1; otherwise, it is equal to 0.
Example:
Str1 = "Bab"
Str2 = "Caba"
Create a Matrix
-- B A B
C 0 0 0
A 0 1 0
B 1 0 1
A 0 1 0
The feature of continuous I substrings is that if str1 [I] And str2 [J] belong to the last character of a public substring, so there must be str1 [I] = str2 [J] & str1 [I-1] = str2 [J-1], intuitively From the matrix, that is, the series represented by the slash "composed of" 1 "are all public substrings, so the longest public substrings must be the longest string of the slash" 1.
Now the problem can be converted. As long as the above matrix is constructed, the matrix can be obtained using the time of N ^ 2, then, go to the matrix and look for the longest slash "1! So now there is a new problem? How can we quickly find the longest slash "1?
Using the DP idea, if str1 [I] = str2 [J], then the length of the common substring containing str1 [I] And str2 [J] must be the length of the common substring containing str1 [I-1] And str2 [J-1] plus 1, so now we can redefine LCS (I, j), that is, LCS (I, j) = LCS (I-1, J-1) + 1, and vice versa, LCS (I, j) = 0. Then the above matrix will look like the following:
-- B A B
C 0 0 0
A 0 1 0
B 1 0 2
A 0 2 0
Now the problem becomes simpler. You only need to take the time of N ^ 2 to construct such a matrix, and then spend the time of N ^ 2 to find the largest value in the matrix, it corresponds to the length of the longest common substring, and the character corresponding to the maximum value is the last character of the longest common substring.
The algorithm can also be improved. We can put the work of finding the maximum length and corresponding characters in the Construction matrix, while constructing and recording the current maximum length and corresponding position, this saves the search time of N ^ 2.
We can also improve the space. If we construct it in the above way, we find that when the value of row I + 1 of the matrix is calculated, the value of row I is useless, even if the longest length appears in row I, we have recorded it with variables. Therefore, the matrix can be reduced to a vector for processing. The current value of the vector corresponds to row I, and the value after the next loop of the vector corresponds to row I + 1.
1 // longest public substring (consecutive) LCS 2 // Deng Chao 3 // 2012.12.4 4 5 # include <iostream> 6 # include <cstring> 7 using namespace STD; 8 9 10 // search for public substrings 11 // LCS record public substrings 12 // return public substrings length 13 int LCS (const char * str1, int len1, const char * str2, int len2, char * & LCs) 14 {15 if (null = str1 | null = str2) 16 {17 return-1; // null parameter 18} 19 20 // The largest compressed string record vector 21 int * c = new int [len2 + 1]; 22 for (INT I = 0; I <len2; ++ I) 23 {24 C [I] = 0; 25} 26 int max_len = 0; // matched length 27 int Pos = 0; // match the final position on str2 28 for (INT I = 0; I <len1; ++ I) 29 {30 for (Int J = len2; j> 0; -- j) // The 31 {32 If (str1 [I] = str2 [J-1]) traversed from the back when updating 33 {34 C [J] = C [J-1] + 1; 35 if (C [J]> max_len) 36 {37 max_len = C [J]; 38 Pos = J-1; 39} 40} 41 else42 {43 C [J] = 0; 44} 45} 46} 47 48 if (0 = max_len) 49 {50 Delete [] C; 51 return 0; 52} 53 54 // obtain the public substring 55 LCS = new char [max_len]; 56 for (INT I = 0; I <max_len; ++ I) 57 {58 LCS [I] = str2 [pos-max_len + 1 + I]; 59} 60 cout <"Pos =" <POS <Endl; 61 Delete [] C; 62 Delete [] LCs; 63 return max_len; 64 65} 66 67 // test68 int main () 69 {70 const char * str1 = "abacaba "; 71 const char * str2 = "Caba"; 72 int len1 = strlen (str1); 73 int len2 = strlen (str2); 74 75 char * LCs; 76 77 int Len = LCS (str1, len1, str2, len2, LCs); 78 cout <"max length =" <Len <Endl; 79 for (INT I = 0; I <Len; ++ I) 80 {81 cout <LCS [I] <""; 82} 83}
Note:
When we update the vector with the longest growth String Length, we traverse the update from the back to the front. Why ??? What will happen when I traverse updates from the past to the next?
Longest public substring