The longest palindrome subsequence: general ideas for subsequence problems

The subsequence problem is a common algorithm problem, and it is not easy to solve.

First of all, the subsequence problem itself is more difficult than substrings and subarrays, because the former is a discontinuous sequence, while the latter two are continuous. Even if you exhaustively list, you may not know how to solve the related algorithm problems. .

Moreover, the subsequence problem is likely to involve two strings, such as the "longest common subsequence" in the previous article. It is really not easy to come up with it without certain processing experience. So this article is going to take a look at the routine of the sub-sequence problem. In fact, there are two templates. As long as you think about these two ideas, you can be sure of the relevant problems.

Generally speaking, this kind of question asks you to find the longest subsequence , because the shortest subsequence is just a character, there is nothing to ask. Once the subsequence and the maximum value are involved, it is almost certain that the dynamic programming technique is examined, and the time complexity is generally O(n^2) .

The reason is simple. Think about a string. How many possible subsequences are there? At least it's exponential. In this case, you don't need dynamic programming skills. What do you want?

Since we want to use dynamic programming, we must define the dp array to find the state transition relationship. The two thinking templates we are talking about are the definition of dp array. Different problems may require different dp array definitions to solve.

One or two ideas

1. The first idea template is a one-dimensional dp array :

int n = array.length;
int[] dp = new int[n];

for (int i = 1; i < n; i++) {
    for (int j = 0; j < i; j++) {
        dp[i] = 最值(dp[i], dp[j] + ...)
    }
}

For example, the "longest increasing subsequence" we wrote, the definition of dp array in this idea is:

In the sub-array  array[0..i] , the length of the sub-sequence (the longest increasing sub-sequence) we require is dp[i] .

Why does the longest increasing subsequence need this kind of thinking? The previous article has made it very clear, because this conforms to the induction method and can find the relationship between the state transitions, and I will not expand it in detail here.

2. The second idea template is a two-dimensional dp array :

int n = arr.length;
int[][] dp = new dp[n][n];

for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        if (arr[i] == arr[j]) 
            dp[i][j] = dp[i][j] + ...
        else
            dp[i][j] = 最值(...)
    }
}

This kind of thinking is used relatively more, especially involving two subsequences of strings/arrays, such as the "longest common subsequence" mentioned above. The meaning of the dp array in this idea is divided into two cases: "only one string is involved" and "two strings are involved".

PS: I have written more than 100 original articles carefully , and I have hand-in-hand brushed with 200 buckle questions, all of which are published in  labuladong's algorithm cheat sheet , which is continuously updated . It is recommended to collect, brush the questions in the order of my articles , master various algorithm routines, and then cast them into the sea of ​​questions.

2.1 When two strings/arrays are involved (such as the longest common subsequence), the meaning of the dp array is as follows:

In sub-arrays  arr1[0..i] and sub-arrays  arr2[0..j] , the length of the sub-sequence (the longest common sub-sequence) we require is dp[i][j] .

2.2 When only one string/array is involved (such as the longest palindrome subsequence described in this article), the meaning of the dp array is as follows:

In the sub-array  array[i..j] , the length of the required sub-sequence (the longest palindrome sub-sequence) is dp[i][j] .

For the first case, you can refer to these two old articles: "Edit Distance" and "Common Subsequence"

Let's borrow the problem of the longest palindrome subsequence to explain in detail how to use dynamic programming in the second case.

2. The longest palindrome subsequence

The problem of "the longest palindrome substring" was previously solved. This time the difficulty is increased to find the length of the longest palindrome subsequence:

a66d5839da8e8dfaf54a94ff21f85d7d.jpeg

We say that the definition of the dp array in this question is: in the substring  s[i..j] , the length of the longest palindrome subsequence is dp[i][j] . You must remember this definition to understand the algorithm.

Why does this problem define a two-dimensional dp array like this? We mentioned many times in the previous article that finding state transition requires inductive thinking. To put it bluntly, it is how to deduce the unknown part from the known results . This definition is easy to generalize and easy to find the state transition relationship.

Specifically, if we want to find  dp[i][j], suppose you know the dp[i+1][j-1] result of the sub-problem  ( s[i+1..j-1] the length of the longest palindrome subsequence), can you figure out  dp[i][j] the value ( s[i..j] the length of the longest palindrome subsequence)?

12578076b32a30c9c86304b531f2a862.jpeg

can! It depends  s[i] and  s[j] characters:

If they are equal , then  s[i+1..j-1] the longest palindrome subsequence in the two additions is  s[i..j] the longest palindrome subsequence:

ad775690b677610ccd3d3bf02206625e.jpeg

If they are not equal , it means that they are unlikely to appear in  s[i..j] the longest palindrome subsequence at the same time , then add them separately to  s[i+1..j-1] see which substring produces the longer palindrome subsequence:

73281af2b3586323f3f550c744edabbe.jpeg

The above two cases are written in code like this:

if (s[i] == s[j]) 
    // They must be in the longest palindrome subsequence 
    dp[i][j] = dp[i + 1][j-1] + 2; 
else 
    // Which palindrome subsequence of s[i+1..j] and s[i..j-1] is longer? 
    dp[i][j] = max(dp[i + 1][j], dp[i][j-1]);

At this point, the state transition equation has been written. According to the definition of the dp array, what we require is   the length of the dp[0][n - 1]entire  slongest palindrome subsequence.

Three, code implementation

First clarify the base case. If there is only one character, obviously the length of the longest palindrome subsequence is 1, that is  dp[i][j] = 1 (i == j).

Because it  i must be less than or equal  jto those  i > j positions, there is no subsequence at all and should be initialized to 0.

In addition, take a look at just written state transition equation, I would like to ask  dp[i][j] you need to know  dp[i+1][j-1], dp[i+1][j], dp[i][j-1] the three positions; take a look at our base case determined, after fill dp array like this:

62adb8ebca4f068df95ef20f8af5348d.jpeg

In order to ensure that dp[i][j]the position in the lower left and right direction has been calculated for each calculation  , it can only be traversed diagonally or reversely :

7bf900498b026dec1ab7b3fa1851bc59.jpeg

I chose to traverse the other way, the code is as follows:

int longestPalindromeSubseq(string s) { 
    int n = s.size(); 
    // all dp arrays are initialized to 0 
    vector<vector<int>> dp(n, vector<int>(n, 0)); 
    // base case 
    for (int i = 0; i <n; i++) 
        dp[i][i] = 1; 
    // Reverse traversal to ensure correct state transition 
    for (int i = n-1; i >= 0; i-- ) { 
        for (int j = i + 1; j <n; j++) { 
            // State transition equation 
            if (s[i] == s[j]) 
                dp[i][j] = dp[i + 1] [j-1] + 2; 
            else 
                dp[i][j] = max(dp[i + 1][j], dp[i][j-1]); 
        } 
    } 
    // the longest return of the entire s The length of the text string 
    return dp[0][n-1]; 
}

So far, the problem of the longest palindrome subsequence is solved.

_____________


Guess you like

Origin blog.51cto.com/15064450/2570828