标签:
动态规划题。
最直观的想法就是用cut[i][j]表示子串s[i..j]的最小分割数,则有如下规则:
1. 如果s[i..j]是回文串,则cut[i][j]=0
2. 如果s[i..j]不是回文串,则枚举分割点,将原字符串切成两个子串,求解子问题。递推公式:cut[i][j] = min{cut[i][k] + cut[k+1][j] + 1},i <= k < j
这样做的时间复杂度是O(n^3),可以引入额外的辅助条件对递推数组降维来优化。
改进后是这样的:
令cut[i]表示子串s[i..n-1]的最小分割数,则有如下规则:
1. 如果s[i..n-1]是回文串,则cut[i] = 0
2. 如果s[i..n-1]不是回文串,则枚举分割点,将原字符串切成两个子串,规定左边的那个串必须是回文串。递推公式:cut[i] = min{cut[k] + 1},i < k < j 且 s[i][k-1]是回文串
时间复杂度降为O(n^2)
上面并没有考虑判断回文串的计算量,实际上这部分包含着大量重复计算, 所以必须要把是否是回文串的信息记录下来,以后要判断的时候直接查表即可。
算回文串也可以用动归解决。令palinp[i][j]表示s[i..j]是否是回文串,则palinp[i][j] = s[i] == s[j] && (j -i > 2 || palinp[i+1][j-1]),这部分的时间复杂度为O(n^2)
代码:
1 int minCut(string s) { 2 if (s.empty()) 3 return 0; 4 5 int len = s.length(); 6 bool **palinp = new bool*[len]; 7 int *cut = new int[len]; 8 9 for (int i = 0; i < len; i++) 10 palinp[i] = new bool[len]; 11 12 for (int l = 1; l <= len; l++) { 13 for (int i = 0; i + l <= len; i++) { 14 palinp[i][i + l - 1] = (s[i] == s[i + l - 1]) && (l <= 2 || palinp[i + 1][i + l - 2]); 15 } 16 } 17 18 for (int i = len - 1; i >= 0; i--) { 19 if (palinp[i][len - 1]) 20 cut[i] = 0; 21 else { 22 cut[i] = len - i - 1; 23 for (int j = i + 1; j < len; j++) { 24 if (palinp[i][j - 1]) 25 cut[i] = min(cut[i], 1 + cut[j]); 26 } 27 } 28 } 29 30 return cut[0]; 31 }
Leetcode#132 Palindrome Partitioning II
标签:
原文地址:http://www.cnblogs.com/boring09/p/4236327.html