题解 | #Palindrome#

Palindrome

https://ac.nowcoder.com/acm/problem/105756

简要题意:给出一个字符串,求增加多少字符能使之回文
方法:串长减去最长回文子序列长度,即增加非最长回文串的内容
传统方法dp[i] [j]表示i到j最长回文串长度
若s[i]==s[j],dp[i] [j]=dp[i+1] [j-1]+2
否则dp[i] [j] = max(dp[i+1] [j],dp[i] [j-1])
注意开一个5005*5005的int数组会爆空间
优化法一:改成short数组,short范围 -32768~32767,即-2^15 ~ 2^15-1

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
string s;
short dp[5005][5005];//i到j的最长回文子序列长度

int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin >> n;
    cin >> s;
    s=" "+s;//使字符串有效下标从1到n
    for(int len=0;len<=n-1;len++){//区间长度
        for(int l=1;l<=n && l+len<=n ;l++){
            int r=l+len;
            if(r==l)    dp[l][r]=1;
            else if(s[l]==s[r])    dp[l][r]=dp[l+1][r-1]+2;
            else    dp[l][r]=max(dp[l+1][r],dp[l][r-1]);
        }
    }
    cout << n-dp[1][n] << "\n";

//    for(int i=0;i<n;i++){
//        for(int j=0;j<n;j++){
//            cout << dp[i][j] << " ";
//        }
//        cout << "\n";
//    }
    return 0;
}

优化法二:01滚动
上述求回文串的解法不好滚动,考虑将串反转后与原串求最长公共子序列。
若s[i]==t[j],则dp[i] [j]=dp[i-1] [j-1]+1
否则dp[i] [j]=max(dp[i-1] [j],dp[i] [j-1])
01滚动时,只需把第一维对2取模,另外(i-1)%2=(i+1)%2

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
string s;
string t;
int dp[2][5005];//i到j的最长回文子序列长度

int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin >> n;
    cin >> s;
    t=s;
    reverse(s.begin(),s.end());
    s=" "+s;t=" "+t;//使字符串下标从1开始,防越界

    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(s[i]==t[j])
                dp[i%2][j]=dp[(i+1)%2][j-1]+1;
            else
                dp[i%2][j]=max(dp[(i+1)%2][j],dp[i%2][j-1]);
        }
    }

    cout << n-dp[n%2][n] << "\n";

//    for(int i=0;i<2;i++){
//        for(int j=0;j<n;j++){
//            cout << dp[i][j] << " ";
//        }
//        cout << "\n";
//    }
    return 0;
}
全部评论
感觉有点小问题j=0的时候j-1那里不是越界了吗
点赞 回复
分享
发布于 2021-09-24 11:27

相关推荐

1 收藏 评论
分享
牛客网
牛客企业服务