这道题还挺复杂的,回来看了好一会儿才想起当时怎么想的。。上道题刚说不要打表,这道题就用了打表。。
总的思路是这样的,从后面往前面打表,最后一个位置的最小分割一定是0,那往前呢,如果当前考虑的位置是start,并且substr(s, i)是回文的,那么如果已知i+1开始的分割次数,那么start这个位置的分割应该就是start原来的和i+1开始的分割次数加1之间的最小值。DP的思想,很直接。
但是我忽略了一个另一个开销很大的地方,那就是每次判断回文的时候。这个跟单词分割还不一样,这个范围很大。最后居然开了个很大的二维数组,记录每个位置的起始结束是不是回文,直接打脸了。。建这个表的时候,我先把两头的回文计算了一遍,当计算中间部分的时候,直接用这两头的结果。其实想法很简单,如果i+1和j-1之间是不是回文已经知道了,那么i和j就不用从头算了,看看i和j位置相不相等,按照情况更新就行了。
这道题应该有更优雅的算法,回头找到了贴上来,先贴我的。
int MAX = 0xfffffff; bool isp[2000][2000]; bool isPalindrome(string &s, int start, int end){ for(int i=start, j=end;i<j;++i, --j){ if(s[i] != s[j]) return false; } return true; } void getPartition(string &s, int start, vector<int> &minpartition){ if(start == s.length()){ minpartition[start] = 0; return; } for(int i=start;i<s.length();++i){ if(isp[start][i]){ if(minpartition[i+1] == MAX) getPartition(s, i+1, minpartition); minpartition[start] = min(minpartition[start],minpartition[i+1]+1); } } } class Solution { public: int minCut(string s) { if(s.length()<=1) return 0; int len = s.length(); memset(isp, 0, sizeof(isp)); for(int i=0;i<len;i++){ isp[0][i] = isPalindrome(s, 0, i); } for(int i=1;i<len;i++){ isp[i][len-1] = isPalindrome(s, i, len-1); } for(int i=len-2;i>0;i--){ for(int j=i;j<len-1;j++){ if(i == j) isp[i][j] = 1; else if(j == i+1) isp[i][j] = s[i]==s[j]; else isp[i][j] = isp[i+1][j-1]&&s[i]==s[j]; } } vector<int> minpartition(len+1, MAX); getPartition(s, 0, minpartition); return minpartition[0]-1; } };
leetcode第一刷_ Palindrome Partitioning II,布布扣,bubuko.com
leetcode第一刷_ Palindrome Partitioning II
原文:http://blog.csdn.net/u012792219/article/details/25076105