Dynamic programming problem example (3): the longest common subsequence/string; the longest palindrome subsequence/substring

Note: The subsequence is not required to be continuous, the substrings are required to be continuous.
1. The longest common subsequence:
Given two sequences, find the longest common subsequence of the two sequences. Example:
Insert picture description here
1.1. Optimal substructure:
Insert picture description here
1.2. Pseudo code:
Insert picture description here
Insert picture description here
Visualization of matrix c and b:
Insert picture description here
1.3. C++ code :

#include <iostream>
#include <vector>
#include <string>
#include <stack>
using namespace std;

string getLCS(string s1, string s2)
{
    
    
//此部分获得最长值
	 int m=s1.length()+1;
	 int n = s2.length()+1;
	 vector< vector<int> > c(m, vector<int>(n)); //计算长度
	 vector< vector<int> > b(m, vector<int>(n)); // 字串遍历
	 for(int i = 0;i<m;i++) {
    
     c[i][0] = 0; } // 初始条件(边界条件)
	 for(int i = 0;i<n;i++) {
    
     c[0][i] = 0; } // 同上
	 for(int i = 0;i<m-1;i++){
    
    
		for(int j = 0;j<n-1;j++){
    
    
			if(s1[i] == s2[j]) {
    
     
				c[i+1][j+1] = c[i][j] + 1; 
				b[i+1][j+1] = 1; // 1 表示相同 
			}
			else if(c[i][j+1]>c[i+1][j]){
    
    
				c[i+1][j+1] = c[i][j+1];
				b[i+1][j+1] = 2; // 2 表示不同 
			}
			else{
    
    
				c[i+1][j+1] = c[i+1][j];
				b[i+1][j+1] = 3; //  3表示不同 
			}
		}
	}
//此部分获得公共子序列
	stack<char> LCSans;
	for(i = m-1,j = n-1; i>=0 && j>=0; ;){
    
    
		if(b[i][j] == 1){
    
    
			LCSans.push_back(s1[i]);
			i--;
			j--;
		}
		else if(b[i][j] == 2)
            i--;
        else
        	j--;
	}
// 此部分输出子序列
	while(!LCSans.empty()) {
    
    
       cout<<LCSans.top();
       LCSans.pop();
   }	 
}

Reference: Dynamic programming solution to the longest common subsequence (LCS)

2. The longest common substring:
replace the longest subsequence else ifjudgment sentence

string getLCS(string str1, string str2) {
    
    
	int m=s1.length()+1;
	int n = s2.length()+1;
	int maxlen = 0;
	int end;
	vector< vector<int> > c(m, vector<int>(n)); //计算长度
	for(int i = 0;i<m;i++) {
    
     c[i][0] = 0; } // 初始条件(边界条件)
	for(int i = 0;i<n;i++) {
    
     c[0][i] = 0; } // 同上
	for(int i = 0;i<m-1;i++){
    
    
		for(int j = 0;j<n-1;j++){
    
    
			if(s1[i] == s2[j]) {
    
     
				c[i+1][j+1] = c[i][j] + 1; 
			}
			else {
    
    
				c[i+1][j+1] = 0;
			}
			if(c[i+1][j+1]>maxlen){
    
    
				maxlen = c[i+1][j+1];
				end = i;
			}
		}
	}
	return str1.substr(end - maxlen + 1, maxlen);
}

Reference: Find the longest common substring of two strings

3. The longest palindrome subsequence: the
characters in the string are symmetrical and are called palindrome. For example, wbcdcbw in the string wabcdcbwq is the palindrome subsequence; bcdcb is the palindrome subsequence.
Solution:
Flip the string s and change it to s', and use the common subsequence method to solve.

string longestPalindrome(string s) {
    
    
    if(s.length()==1) return s;//大小为1的字符串必为回文串
    string rev=s;//rev存放s反转结果
    string res;//存放结果
    std::reverse(rev.begin(),rev.end());
    if(rev==s) return s;
	//从此开始调用最长公共子序列算法。

4. The longest palindrome substring:
4.1. Dynamic programming version:
S stands for string, i and j stand for start and end positions.
Initial condition (boundary condition): When the length is less than 2, the range of dp(i + 1, j -1) is wrong, so the length is 1, 2 is the boundary condition
a) dp[i][i] = true (used in the code 1 means)
b) If S[i] = S[i+1], then dp[i][i+1] = true The
state transition equation:
a) If (dp(i + 1, j -1) == true && S[i] == S[j]) then dp(i, j) = true
b) if (dp(i + 1, j -1) == false || S[i] != S[j ]) then dp(i, j) = false

class Solution {
    
    
public:
    string longestPalindrome(string s) {
    
    
        int len=s.size();
        if(len==0||len==1)
            return s;
        int start=0;//回文串起始位置
        int max=1;//回文串最大长度
        vector<vector<int>>  dp(len,vector<int>(len));//定义二维动态数组
        for(int i=0;i<len;i++)//初始化状态
        {
    
    
            dp[i][i]=1; //单个元素是回文串
            if(i<len-1&&s[i]==s[i+1]) //两个元素相同也是回文串
            {
    
    
                dp[i][i+1]=1;
                max=2;
                start=i;
            }
        }
        for(int l=3;l<=len;l++)//l表示检索的子串长度,等于3表示先检索长度为3的子串
        {
    
    
            for(int i=0;i+l-1<len;i++)
            {
    
    
                int j=l+i-1;//终止字符位置
                if(s[i]==s[j]&&dp[i+1][j-1]==1)//状态转移
                {
    
    
                    dp[i][j]=1;
                    start=i;
                    max=l;
                }
            }
        }
        return s.substr(start,max);//获取最长回文子串
    }
};

Reference material: C++ solution of the longest palindrome substring 3: dynamic programming

4.2. The central expansion method:
how to retrieve the text string in the central diffusion method?
Starting from each position, spread to both sides. End when it is not a palindrome. For example, str=acdbbdaawe need to find the longest palindrome starting from the first b (position 3). How to find?
First, look for the same character as the current position on the left until it encounters inequality.
Then go to the right to find the same character as the current position until it encounters inequality.
Finally, it spreads in both directions until left and right are not equal. As shown in the figure below:
Insert picture description here
a window size (len) will appear at each position spreading to both sides. If len>maxLen(used to indicate the length of the longest palindrome). The updated maxLenvalue.
Because the last thing we want to return is the specific substring, not the length, so we also need to record the starting position (maxStart) at maxLen, that is, maxStart=len at this time.

string LPS(string s)
{
    
    
	int maxstart = 0;
	int maxlen = 1;
	int start = 0;
	int len = 1;
	if(s.size()<=1) return s;
	for(int i = 0;i<s.size();i++){
    
    
		int l = i--;
		int r = i++;
		while(l>=0 && s[l] == s[i]) {
    
     start = l; len++; l--}
		while(r<s.size() && s[r] == s[i]) {
    
     len++; r++}
		while(l>=0 && r<s.size() && s[l] == s[r]) {
    
     
			start= l;
			l--;
			r++;
			len = len+2;
		}
		if(len > maxlen) {
    
     maxstart  = start; maxstart = start;}
		len = 1;
	}
	return s.substring(maxstart,maxlen);
}

Reference material: central diffusion method

to sum up:

1. The key to dynamic programming: finding the optimal substructure, that is, finding the initial state and state transition equation.

Guess you like

Origin blog.csdn.net/qq_33726635/article/details/105933862
Recommended