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.
思路:第一种按照DFS搜索的方式,如果有了更小的切分,更新ans,最后输出ans,这样做直接TLE.
第二种思路,就应该考虑DP,DP[i]代表前i个元素的最小切分,那么DP[i] = min{ 1 + DP[j], (j+1 .. i 是Palindrome)} #不要只是想DP[i-1] 这种思路中复杂度是O(n^3), i,j 以及j+1..i判断是否是Palindrome. 依然TLE
第三种思路:对于上边的进行如何进行优化,到O(n^2) .那么对于回文来说,也可以继续DP. dp[i,j] = (s[i] == s[j] && dp[i+1,j-1]) 这个地方很有意思,比如:"abbab" 当看i=3 a的时候,判断[abba]是回文的时候,bb是否是回文已经判断过了,只要用dp寸下来就可以了。用了Memorize的技术,判断Palindrome就是O(1)了,整体复杂度优化到了O(n^2).题目里面的话,其实就是dp[j+1,i] = s[j+1] == s[j] && dp[j+2,i-1].
class Solution { public: int ans; vector<string> ans_v; bool IsPalindrome(const string & s){ int i = 0; int j = s.size() -1; //这里之前有一个bug,while(i != j) 比如 bb的情况,一下子 i = 1, j = 0, 然后就会越界访问 core dump while(i < j){ if (s.at(i) == s.at(j)){ i++; j--; }else{ return false; } } return true; } //这里dfs的意思是说从start的位置出发,找最近的回文串,然后继续递归 // abbab-> 'a' 'b' 'b' 'a' 'b' path OK // abbab-> 'a' 'b' 退栈直到 path // abbab-> 'a' 'b' 'bab' path OK // abbab-> 'a' 'bb' 'a' 'b' path OK // abbab-> '' path --> 一直退栈 // abbab-> 'abba' 'b' path OK //如果是显式的给出图 /* root / \ a abba / \ \ b 'bb' 'b' / \ \ \ b 'bab' 'a' OK / \ \ a OK 'b' / \ b OK / OK 一目了然,你可以理解为图的DFS,也可以理解为树的DFS,Path就是记录路径的。 因为本质是一棵树,不会重复访问,也不需要VISIT数组 for循环本质是判断当前节点下有多少领接的边 以后对于这种题目,先写出表达式tree或者graph,然后再去遍历 */ void dfs(string s, int start, vector<string> & path){ if (start == s.size()){ ans = ans > path.size() -1 ? path.size() -1 : ans; return; } for(int i = start + 1; i <= s.size(); i++){ //确定当前start位置出发的回文串 string sub_s = s.substr(start,i - start); //cout << "start: "<<start<<" i: "<<i<<" sub_s: " << sub_s << "\n"; if (IsPalindrome(sub_s)){ //cout << "here: " << sub_s << "\n"; path.push_back(sub_s); dfs(s,i,path); path.resize(path.size() -1); } } } int minCut(string s) { ans = 1<<30; ans_v.clear(); dfs(s,0,ans_v); return ans; } };
class Solution { public: bool IsPalindrome(const string & s){ int i = 0; int j = s.size() -1; //这里之前有一个bug,while(i != j) 比如 bb的情况,一下子 i = 1, j = 0, 然后就会越界访问 core dump while(i < j){ if (s.at(i) == s.at(j)){ i++; j--; }else{ return false; } } return true; } int minCut(string s) { // Start typing your C/C++ solution below // DO NOT write int main() function if (s.size() == 0){ return 0; } //DP[i] = min{ 1+ DP[j]} "j+1..i" is palindrome int * dp = new int[s.size()]; dp[0] = 0; for(int i = 1; i < s.size(); i++){ dp[i] = i; for(int j = i -1; j >= -1; j--){ string sub_s = s.substr(j+1,i - j); if (IsPalindrome(sub_s)){ //这里刚开始有一个BUG, min(dp[i],dp[j]) + 1 会导致每次都加1,其实是要求 min{DP[j] + 1} dp[i] = j >=0 ? min(dp[i],dp[j] + 1) : 0; } } } int ans = dp[s.size() -1]; delete []dp; return ans; } };
class Solution { public: bool IsPalindrome(const string & s){ int i = 0; int j = s.size() -1; //这里之前有一个bug,while(i != j) 比如 bb的情况,一下子 i = 1, j = 0, 然后就会越界访问 core dump while(i < j){ if (s.at(i) == s.at(j)){ i++; j--; }else{ return false; } } return true; } int minCut(string s) { // Start typing your C/C++ solution below // DO NOT write int main() function if (s.size() == 0){ return 0; } //DP[i] = min{ 1+ DP[j]} "j+1..i" is palindrome int * dp = new int[s.size()]; //先写一个O(n^2)空间复杂度的版本 int ** pl = new int*[s.size()]; for(size_t i = 0; i < s.size(); i++){ pl[i] = new int[s.size()]; pl[i][i] = 1; } dp[0] = 0; for(int i = 1; i < s.size(); i++){ dp[i] = i; for(int j = i -1; j >= -1; j--){ //string sub_s = s.substr(j+1,i - j); //if (IsPalindrome(sub_s)){ if (j + 2 <= i -1){ pl[j+1][i] = s.at(j+1) == s.at(i) && pl[j+2][i-1]; }else{ pl[j+1][i] = s.at(j+1) == s.at(i); } if (pl[j+1][i]){ dp[i] = j >=0 ? min(dp[i],dp[j] + 1) : 0; } } } int ans = dp[s.size() -1]; delete []dp;
//delete pl return ans; } };