动态规划之分割回文串

16 篇文章 0 订阅
13 篇文章 0 订阅

分割回文串

 给定字符串 s, 需要将它分割成一些子串, 使得每个子串都是回文串.最少分割几次?
 样例 1:
 输入:
 	"a"
 输出:
 	0
 解释: "a" 本身就是回文串, 无需分割
 
 样例 2:
 输入:
 	"aab"
 输出:
 	1
 解释: 将 "aab" 分割一次, 得到 "aa" 和 "b", 它们都是回文串.

解答:
定义DP[i][j]为字符串s长度为i时,前j个字符使得每个子串都是回文串并且s的第j+1到第i个字符组成的子串也是回文的最小分割成次数.
则DP[i][j] = DP[j][j]+ 1 其中s[j]->s[i-1]子串是回文的情况下;
否则DP[i][j]不可取,即DP[i][j] = MAX;
取DP[i][i]为DP[i][0]–>DP[i][i-1]的最小值

状态转换方程:
DP[i][j] =  DP[j][j]+ 1 	{s[j]->s[i-1]子串是回文}
			MAX				{s[j]->s[i-1]子串不是回文}
			min(DP[i][k])	{0<= k < j, i==j}
class Solution {
public:
    /**
     * @param s: A string
     * @return: An integer
     */
    int minCut(string &s) {
        // write your code here
        /*
        定义DP[i][j]为字符串s长度为i时,前j个字符使得每个子串都是回文串的最小分割成次数.
        则DP[i][j] = min(DP[i][j], min(DP[k][k]+ 1)) {0 =< k <= i} 其中s[k+1]->s[i]子串是回文的情况下;
        否则DP[i][j]不可取,即DP[i][j] = -1;
        
        取DP[i][i]为DP[i][0]-->DP[i][i-1]的最小值
        */
        
        if(s.empty()){
            return -1;
        }
        
        const int MAX = 2 * s.size();
        int m = s.size() + 1;
        int n = m;
        
        int** dp = new int*[m];
        for (int i = 0; i < m; i++) {
            dp[i] = new int[n];
            for (int j = 0; j < n; j++) {
                dp[i][j] = MAX;
            }
        }
        
        for (int i = 0; i < m; i++) {
            //dp[i][0] = isBackWord(s.substr(0, i)) ? 0 : MAX;
            dp[i][0] = isBackWord(s, 0, i-1) ? 0 : MAX;
        }
        for (int i = 1; i < 2; i++) {
            dp[0][i] = 0;
            dp[1][i] = 0;
        }
        
        // s长度从1到m时
        for (int i = 1; i < m; i++) {
            // 判定整个子字符串是否是回文
            if(dp[i][0] == 0){
                dp[i][i] = 0;
                continue;
            }
            // 分别计算前0到前i个字符子串为回文时的情况
            for (int j = 1; j < i; j++) {
                //if(isBackWord(s.substr(j, i - j))){
                if(isBackWord(s, j, i-1)){
                    dp[i][j] = dp[j][j] + 1;
                    dp[i][i] = min(dp[i][i], dp[i][j]);
                }
            }
        }
        
        int nMin = dp[m-1][n-1];
        for (int i = 0; i < m; i++) {
            delete[] dp[i];
        }
        delete[] dp;
        return nMin;
    }
    
    bool isBackWord(const std::string& s){
        int i = 0;
        int j = s.size() - 1;
        while(i < j){
            if(s[i++] != s[j--]){
                return false;
            }
        }
        return true;
    }
    
    bool isBackWord(std::string& s, int begin, int end){
        
        while(begin < end){
            if(s[begin++] != s[end--]){
                return false;
            }
        }
        return true;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值