题目大意:
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.
意思就是:
给定字符串s,求得最小的划分数,使得划分的字符串都是回文串。
做题思路:
1,可以借鉴Palindrome Partitioning的做题结果,把所有的情况都存下来。最后求得最大数。但是这样不是time limited就是memory limited。
2,做题的过程中,我还采用了一种错误的做题思路,即贪心算法——从第一个字符开始,求的最长的回文,然后从该回文的下一个字符开始继续求。最后证明结果是错的。、
3,这道题目太难,自己想不出。最后网上找了思路——动态规划。
a,改良前的动态规划。
类似矩阵连乘的动归思路。
dp[i][j]=min(dp[i][k]+dp[k+1][j]+1), i<=k<j.
dp[i][j]表示从第i个字符到第j个字符,最小的切分数。但是用这个方程的时间是O(n^3),简化dp[i][j]为dp[i],表示从0到i的minCut.
b,改良后的动态规划。
dp[i]=min(dp[k]+1, dp[k]+i-k), 0<=k<i.
(s[k+1, i]是回文串) (s[k+1, i]不是回文串)
c,注意:判断字符串是否是回文,也不能用Palindrome Partitioning的方法了,因为动态规划很多子问题。这些字问题中判断字符串是否是回文的时候,有很多字符串是重复的。所以有必要采用动态规划的方式——递归加记忆化。详见代码。
代码如下:
class Solution { public: int minCut(string s){ string::size_type str_length = s.length(); if(str_length ==0 || str_length == 1){ return 0; } int i; min.resize(str_length+1); min[0] = 0; vector<int> hehe; for(i=0;i<str_length;i++){ hehe.push_back(-1); } for(i=0;i<str_length;i++){ track.push_back(hehe); } int tmp = 0, result, k; for(i=1;i<str_length+1;i++){ //string nn = s.substr(0,i); if(ifpalindrome(s,0,i-1)){ min[i] = 0; } else{ result = i; for(k=0;k<i;k++){ //string mm = s.substr(k,i-k); if(ifpalindrome(s,k,i-1)){ tmp = min[k] + 1; } else{ tmp = min[k] + i - k; } if(tmp < result){ result = tmp; } } min[i] = result; } } return min[str_length]; } bool ifpalindrome(string& s,int i,int j){ if(i>j){ return false; } if(track[i][j] != -1){ return track[i][j]; } if(i == j){ return track[i][j]=1; } if(s[i] != s[j]){ return false; } else{ if(j-i == 1){ return track[i][j]=1; } else{ return track[i][j] = ifpalindrome(s,i+1,j-1); } } } private: vector<int> min; vector< vector<int> > track; };