非常非常难,用dfs完全过不了。即使把每个substring是不是palindrome全算好了放在dp数组里也会挂。必须dp了。
算法:
- 首先把每个substring是不是palindrome先二维dp的做出来。其实这一步可以合在下一步里,但是下一步本身的logic就够难想了,所以这里分开来写。
- 一维dp(为神马是一维啊!!头一次看这样的一维啊!!一维dp却是两层循环啊卧槽!!!),d[i]表示str[i..n]最少切几刀能保证substring全是palindrome。
- 把d[i]先赋成最大值。
- i从后往前,然后j在每个i处从前往后。如果str[i, j]是个palindrome,那么可以在j 和j + 1中间切一刀,这样的#就是d[j + 1] + 1([i..j], 一刀, [j + 1..本来有几刀])。这样切法可能就比之前算的d[i]小了,于是update。
public int minCut(String s) {
int n = s.length();
boolean[][] isPalin = new boolean[n][n];
for (int i = n - 1; i >= 0; i--) { // i is always <= j
for (int j = i; j < n; j++) {
boolean isPalindrome = s.charAt(i) == s.charAt(j)
&& (j - i < 2 || isPalin[i + 1][j - 1]);
isPalin[i][j] = isPalindrome;
}
}
int[] d = new int[n];
// initialize as cut between every letter
for (int i = 0; i < n; i++) {
d[i] = n - 1 - i;
}
for (int i = n - 1; i >= 0; i--) {
for (int j = i; j < n; j++) {
if (isPalin[i][j]) {
if (j == n - 1)
d[i] = 0;
else
d[i] = Math.min(d[i], d[j + 1] + 1);
}
}
}
return d[0];
}
9.16更新
-------------
这道题一开始我用的是dfs,结果直接tle。突然我又想,题目不正是一个搜索最短路径的搜索问题么,用bfs!结果用了bfs还是tle,然后我又用了哈希set对bfs进行剪枝,没想到还是tle!! 看了答案才发现这道题目是枚举分割点的一维dp!!!。这道题看起来,真的很不想像一维DP,所以当看到答案的时候,我还是觉得很惊讶的。
下面是喜刷刷的题解。注意这里的一个trick是让dp[0]=-1。
整体的思路是一维DP。DP[i]表示长度为i的prefix:s[0: i-1]的min cut数量。
DP[i] = min (DP[j] + 1) ,对所有 0<=j<i,且s[j: i-1]为palindrome。
和I同样的技巧,用DP先计算存储一个palindrome判断矩阵isPal[i][j],便于后面一维DP计算中能迅速判断s[j: i-1]是否为palindrome。class Solution { public: int minCut(string s) { int n = s.size(); if(n<=1) return 0; vector<vector<bool>> isPal(n, vector<bool>(n, false)); for(int i=n-1; i>=0; i--) { for(int j=i; j<n; j++) { if((i+1>j-1 || isPal[i+1][j-1]) && s[i]==s[j]) isPal[i][j] = true; } } vector<int> dp(n+1,INT_MAX); dp[0] = -1; for(int i=1; i<=n; i++) { for(int j=i-1; j>=0; j--) { if(isPal[j][i-1]) { dp[i] = min(dp[i], dp[j]+1); } } } return dp[n]; } };