Leetcode第1312题 让字符串成为回文串的最少插入次数C++解法

刚做过编辑距离的,我就想直接复制一个反转字符串,然后这两个字符串相同,前几个还可以的,但是到“leetcode”这个时,就不行了。仔细想这两个问题还是不等价,72题中的编辑距离中的操作包括更改操作,但是本题中的操作只有插入,所以果然不行。
然后我又想从两边向中间靠拢,leetcode倒是通过了,第18个案例"zjveiiwvc"就通不过了

class Solution {
public:
    int minInsertions(string s) {
        int n=s.size();
        if(n<2) return 0;
        int dp[n+2],low=1,high=n;
        memset(dp,0,sizeof(dp));
        while(low<high)
            {
                if(s[low-1]==s[high-1])
                    {dp[low]=dp[low-1];
                                    ++low;--high;}
                else
                    {dp[low]=dp[low-1]+1;
                    ++low;}

            }
        return dp[low-1];
    }
};

然后我想是不是要从中间到两边,而中间的选定是要从0-(n-1)遍历一遍。然后我发现会出现偶数序列和奇数序列问题,再然后想到最长回文子串也出现过,我又想结果是不是等于字符串长度-最长回文子串长度,然后仔细一想,肯定不对的。但是问题到了这里,想明白了,其实应该等于字符串长度-最长回文子序列长度。方法就是以原来最长回文子序列中心字符为中心,不在原来回文字序列中的字符,对称插入即可。

class Solution {
public:

    int longestPalindromeSubseq(string s) {
        int n=s.size();
        int dp[n][n];        
        memset (dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        dp[i][i]=1;
        for(int i=n-1;i>=0;--i)
        {
            for(int j=i+1;j<n;++j)
            if(s[i]==s[j])
            dp[i][j]=dp[i+1][j-1]+2;
            else
            dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
        }
        return dp[0][n-1];
    }

    int minInsertions(string s) {
        return s.size()-longestPalindromeSubseq(s);
    }
};

想明白上面之后,我在想要是不用最长回文子序列该如何呢?之前做的戳气球其实可以有点可以借鉴的。我们假设要求(i,j)区间,那么我们可以这样想(i+1,j)和(i,j-1)和(i+1,j-1)区间已知。如果s[i]和s[j]相等,那么dp[i][j]=dp[i+1][j+1],如果不相等,则选取dp[i][j-1]和dp[i+1][j]之间的最小值加一即可。因为s[i]和s[j]不等了,所以我们需要任意增加其中一个就好,但是这样就转化为(i+1,j)和(i,j-1)区间的问题了。
手写的时候,肯定是斜着写更符合,但是写代码太难了,只能从倒着写,

class Solution {
public:

    int minInsertions(string s) {
        int n=s.size();
        if(n<2) return 0;
        int dp[n][n];
        memset(dp,0,sizeof(dp));
        for(int i=n-2;i>=0;--i)
            for(int j=i+1;j<n;++j)
                if(s[i]==s[j])
                    dp[i][j]=dp[i+1][j-1];
                else
                    dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
        return dp[0][n-1];
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值