hihoCoder #1323 : 回文字符串

最近做了一道hihoCoder上面的一道题目觉得还挺有意思,题意是:给定一个字符串S,至少需要几次增删改操作可以把S变成一个回文字符串?一次操作可以在任意位置插入一个字符,或者删除任意一个字符,或者把任意一个字符修改成任意其他字符。
这题一开始也想到了动态规划的解法,但是最后思路有问题少考虑了一种情况,正确的做法是建立一个二维数组dp[N][M]表示从第N个字符到第M个字符的结果!但是在更新的横纵坐标的时候要注意顺序,之前就是因为没考虑清楚导致跑出来的结果是错的,其实这道题目要是理解透彻了还是对于理解dp有帮助的。
具体递推方程:当s[i] == s[j]时有dp[i][j] = dp[i+1][j-1],这个式子的意思就是当你找到两个字符相等的时候最优的解就是它里面一层的结果即dp[i+1][j-1](左边界加1并且有边界减去1),这样从中心往外加下去。当s[i] != s[j]的时候就要考虑增、删、改这三种操作了,仔细分析你会发现其实增和删的操作是一样的增加一个字符和删除一个字符的效果是一样的这时的递推关系式为 dp[i][j] = min(dp[i+1][j],dp[i][j-1],dp[i+1][j-1]);这个递推关系的意思就是要么增加或删除左边的一个字符,要么增加或删除右边的一个字符,要么修改两边中的一个,就有三种选择,选择其中最优的一种情况就得到了最后的结果。但是特别注意的一点是dp二维数组的遍历顺序是第一维i从len-1到0,第二维j从i+1到len-1,这样就能保证每次递推都是字符串从i到j的最优情况。


#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp[N][N];
int min(int a, int b, int c)
{
    return min(min(a, b), c);
}
int main()
{
    string str;
    cin>>str;
    int len = str.length();
    memset(dp, 0, sizeof(dp));
    for(int i=len-1; i>=0; i--)
    {
        for(int j=i+1; j<len; j++)
        {
            if(str[i] == str[j])
                dp[i][j] = dp[i+1][j-1];
            else
                dp[i][j] = min(dp[i+1][j], dp[i][j-1], dp[i+1][j-1]) + 1;
        }
    }
    cout<<dp[0][len-1]<<endl;
    return 0;
}


发布了106 篇原创文章 · 获赞 69 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/u014142379/article/details/51761551