合并回文子串

题目链接

在这里插入图片描述

思路

① 扩展一个回文串,只要在首末各自加上一个相同的字符即可。

③ 求的是最长的回文子串长度,所以只要保存字符串A,B融合过程中的最大回文串长度就行。

②那么现在判断 A,B融合过程中的回文串
想要让 串 A 的 区间 i ~ j 和串B的区间 k ~ l 组成一个回文串,并且组成后的新字符串中 A ,B各自原字符相对位置不变,所以这个回文串 A[i] 一定在 A[j] 前面 ,B[k]一定在B[l] 前面 ,此时再回顾下 ① 那么这个回文串首末的的字符
组合有以下 4 种

1.A[i] = A[j] i 首 j末
2.B[k] = B[l] k首 l末
3.A[i] = B[l] i 首 l末
4.B[k] = A[j] k 首 j末

在这种情况下 只要保证 以上 4种任意一种除去首末字符后的子串仍是一个回文,且A,B各自字符顺序 不混乱的回文串, A 的 区间 i ~ j 和串B的区间 k ~ l 就可以组成一个回文串。你可以发现这是一个递归的问题于是便可以递归的解决这一个问题了。

④ 考虑边界问题
1.单个字符肯定是回文,
2.子问题是空串组成也算满足条件的回文

code

dfs

#include<bits/stdc++.h>
using namespace std;
#define IOS std::ios_base::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);// 快读

int dp[53][53][53][53];

string a,b;
int ans;
bool dfs(int i,int j,int k,int l){
   // cout << i << " " << j << " " << k <<  " " << l << endl;
     if(~dp[i][j][k][l])
        return dp[i][j][k][l];
    if(i == j && l == k)//空
        return false;
    if(j < i || l < k)//空
        return false;
    if(j - i == 1 && l - k == 1 && a[i-1] == b[k - 1]){//AB串各自剩下一个
        ans = max(ans,2);
          return true;
    }
    
    if((j - i == 1 && k == l) || (l - k == 1 && i == j) ){//A或B剩下一个字符,另一个串没有字符剩下
        ans = max(1,ans);
        return true;
    }
    
    if(j - i == 2 && k == l && a[i-1] == a[i]){//A串剩下2个字符
        ans = max(2,ans);
        return true;
    }
    if(l - k == 2 && i == j && b[k-1] == b[k]){//B串剩下2个字符
        ans = max(2,ans);
        return true;
    }
   
    bool f = false;
    if(a[i-1] == a[j-2])
        f |= dfs(i + 1,j - 1,k,l);
    if(b[k - 1] == b[l - 2])
        f |= dfs(i,j,k + 1,l - 1);
    if(a[i-1] == b[l-2])
        f |= dfs(i + 1,j,k,l - 1);
    if(a[j-2] == b[k-1])
        f |= dfs(i,j-1,k + 1,l);
    //cout << f << endl;
    if(f)
        ans = max(ans,j - i + l - k);
    
    return dp[i][j][k][l] = f;
}

int main(){
    int T;    cin >> T;
    while(T--){
        ans = 0;
        memset(dp, -1 ,sizeof dp);
        cin >> a >> b;
        int az = a.size();
        int bz = b.size();
        
        for(int i = 1;i <= az; ++i)
            for(int j = 1; j <= bz; ++j)
                for(int v = 1; v <= az && v + i <= az + 1; ++ v)
                    for(int u = 1; u <= bz && u + j <= bz + 1; ++ u)
                dfs(v,v + i,u,u + j);
        cout << ans << endl;
    }
    return 0;
}

改成迭代 ,枚举区间长度即可,通过状态转移方程不难发现,长区间一定要由短区间来更新,所以先处理短区间,再处理长区间,所以枚举从小到大分别枚举两个串的长度即可

#include<bits/stdc++.h>
using namespace std;
bool dp[53][53][53][53];
int main(){
    int T;    cin >> T;
    while(T--){
        string a,b;    cin >> a >> b;
        int az = a.size(),bz = b.size();
        int ans = 0;
        for(int l1 = 0; l1 <= az; ++l1)
        for(int l2 = 0; l2 <= bz; ++l2)
        for(int i = 1; i + l1 - 1 <= az; ++i)//以i为起点 长度为l的区间 区间端点为 i + l - 1 对应字符位置 i + l -2
        for(int j = 1; j + l2 - 1 <= bz; ++j){
            bool f = false;
            if(l1 + l2 <= 1)
                f = true;
            if(i + l1 - 2 >= 0 && a[i-1] == a[i + l1 - 2] && dp[i+1][i + l1 - 1][j][j + l2])
                f = true;
            if(j + l2 - 2 >= 0 && b[j-1] == b[j + l2 - 2] && dp[i][i + l1][j+1][j + l2 - 1])
                f = true;
            if(j + l2 - 2 >= 0 && a[i-1] == b[j + l2 - 2] && dp[i + 1][i + l1][j][j + l2 -1])
                f = true;
            if(i + l1 - 2 >= 0 && b[j-1] == a[i + l1 - 2] && dp[i][i + l1 - 1][j + 1][j + l2])
                f = true;
            dp[i][i + l1][j][j + l2] = f;
            if(f)
                ans = max(ans,l1 + l2);
        }
        cout << ans << endl;
    }
    
    return 0;
}
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值