Ejemplo de problema de programación dinámica (3): la subsecuencia / cadena común más larga; la subsecuencia / subcadena de palíndromo más larga

Nota: No se requiere que la subsecuencia sea continua, se requiere que la subcadena sea continua.
1. La subsecuencia común más larga:
Dadas dos secuencias, encuentre la subsecuencia común más larga de las dos secuencias. Ejemplo:
Inserte la descripción de la imagen aquí
1.1. Subestructura óptima:
Inserte la descripción de la imagen aquí
1.2. Pseudocódigo:
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Visualización de la matriz cyb:
Inserte la descripción de la imagen aquí
1.3. Código C ++ :

#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();
   }	 
}

Referencia: solución de programación dinámica para la subsecuencia común más larga (LCS)

2. La subcadena común más larga:
reemplaza la else ifsentencia de juicio posterior más larga

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);
}

Referencia: Encuentre la subcadena común más larga de dos cadenas

3. La subsecuencia palíndromo más larga: los
caracteres de la cadena son simétricos y se denominan palíndromo. Por ejemplo, wbcdcbw en la cadena wabcdcbwq es la subsecuencia palíndromo; bcdcb es la subsecuencia palíndromo.
Solución:
voltee la cadena sy cámbiela por s ', y use el método de subsecuencia común para resolver.

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. La subcadena palíndromo más larga:
4.1 Versión de programación dinámica:
S significa cuerda, iyj significan posiciones inicial y final.
Condición inicial (condición de límite): cuando la longitud es menor que 2, el rango de dp (i + 1, j -1) es incorrecto, por lo que la longitud es 1, 2 es la condición de límite
a) dp [i] [i] = verdadero (usado en el código 1 significa)
b) Si S [i] = S [i + 1], entonces dp [i] [i + 1] = verdadero La
ecuación de transición de estado:
a) Si (dp (i + 1, j -1) == verdadero && S [i] == S [j]) entonces dp (i, j) = verdadero
b) si (dp (i + 1, j -1) == falso || S [i]! = S [j ]) entonces dp (i, j) = falso

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);//获取最长回文子串
    }
};

Material de referencia: solución C ++ de la subcadena 3 del palíndromo más larga: programación dinámica

4.2 El método de expansión central:
¿cómo recuperar la cadena de texto en el método de difusión central?
Comenzando desde cada posición, extiéndase a ambos lados. Termina cuando no es un palíndromo. Por ejemplo, str=acdbbdaanecesitamos encontrar el palíndromo más largo a partir de la primera b (posición 3). ¿Como encontrar?
Primero, busque el mismo carácter que la posición actual a la izquierda hasta que encuentre desigualdad.
Luego vaya a la derecha para encontrar el mismo carácter que la posición actual hasta que encuentre desigualdad.
Finalmente, se propaga en ambas direcciones hasta que la izquierda y la derecha no son iguales. Como se muestra en la figura siguiente:
Inserte la descripción de la imagen aquí
aparecerá un tamaño de ventana (largo) en cada posición que se extenderá a ambos lados. Si len>maxLen(usado para indicar la longitud del palíndromo más largo). El maxLenvalor actualizado .
Debido a que lo último que queremos devolver es la subcadena específica, no la longitud, también necesitamos registrar la posición inicial (maxStart) en maxLen, es decir, maxStart = len en este momento.

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);
}

Material de referencia: método de difusión central

para resumir:

1. La clave de la programación dinámica: encontrar la subestructura óptima, es decir, encontrar el estado inicial y la ecuación de transición de estado.

Supongo que te gusta

Origin blog.csdn.net/qq_33726635/article/details/105933862
Recomendado
Clasificación