[LeetCode] Palindrome Partitioning II

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.

http://blog.csdn.net/yutianzuijin/article/details/16850031

定义状态 f(i,j) 表示区间 [i,j] 之间最小的 cut 数,则状态转移方程为
f(i, j) = min { f(i, k) + f(k + 1, j) } , i  <=k <= j, 0 < i <=  j <= n

我们求解的是整个字符串的最小cut数,可以从字符串的头开始,也可以从尾部开始

原问题的目的是求一个最小的划分,如果利用count矩阵则会求从位置i开始的每一个可能划分,实际上这是在做无用功。原因就在于f矩阵的第二维为划分个数,这一维对求最小值问题没有意义,我们可以去掉。所以我们重新定义一个新的一维count数组,用来表示从位置i开始到最后的最小划分个数。这时有公式:

公式的含义是,从i开始的字符串的最小划分为:如果从位置i到位置j的子串是回文串,则从i开始的划分可以通过将i到j的子串看作划分的一部分,然后加上从j+1位置开始的子串最小划分,并选择可能情况中的最小值即为从i开始的最小划分。

所以可以分两步求解:

1. 计算 p[i][j],表示s[i][j]是否是回文字串,

2 计算f[i],也就是count[i]

class Solution {
    public:
        int minCut(string s) {

            const int n = s.size();
            bool p[n][n]; // whether s[i,j] is palindrome
            fill_n(&p[0][0], n * n, false);
            for (int i = n - 1; i >= 0; --i)
                for (int j = i; j < n; ++j)
                    p[i][j] = s[i] == s[j] && ((j - i < 2) || p[i + 1][j - 1]);

            int f[n]; // s[i,n-1] has cut number
            for (int i = 0; i < n; ++i)
            {
                f[i] = n-1-i;
            }

            for (int i = n - 1; i >= 0; --i)
            {
                for (int j = i; j < n; ++j)
                {
                    if(p[i][j])
                    {
                        if(j == n-1)
                            f[i] = 0;
                         else
                             f[i] = min(f[j+1]+1, f[i]);
                    }
                }
            }

#if 0
            for (int i = 0; i < n; ++i) 
            {
                cout << f[i] << "	";
            }
            cout << endl;
#endif
            return f[0];
        }
};

转一个,更加紧凑的code

// LeetCode, Palindrome Partitioning II
// 时间复杂度 O(n^2),空间复杂度 O(n^2)
class Solution {
    public:
        int minCut(string s) {
            const int n = s.size();
            int f[n+1];
            bool p[n][n];
            fill_n(&p[0][0], n * n, false);
            //the worst case is cutting by each char
            for (int i = 0; i <= n; i++)
                f[i] = n - 1 - i; // 最后一个 f[n]=-1
            for (int i = n - 1; i >= 0; i--) {
                for (int j = i; j < n; j++) {
                    if (s[i] == s[j] && (j - i < 2 || p[i + 1][j - 1])) {
                        p[i][j] = true;
                        f[i] = min(f[i], f[j + 1] + 1);
                    }
                }
            }
            return f[0];
        }
};
原文地址:https://www.cnblogs.com/diegodu/p/3853537.html