这道题是DP。那么一开始很自然的想出了O(n^3)的方法。就是预处理是否是Palindrome的boolean[][],话费O(n^3)。然后处理i到j段件的cut数目int[][]也花O(n^3)时间,因为i和j两层循环,中间又要遍历一次i和j之间的分割点。
但是网上看了一下两者都可以化简到O(n^2)。前者也是个DP,因为valid[i][j]依赖于valid[i+1][j-1]和s[i]==s[j]。而后面其实多求了许多不需要的信息,我们只要cut[0][j]就行了,而这里把所有的cut[i][j]都求了。这有点像Floyd算法求了所有点之间最短距离,所以复杂度就比Dijkstra高了一维类似。所以后者的转移方程式cut[i]为cut[j]+1,如果valid[j+1][i]的话。这里要注意的是,如果valid[i][j],那么直接就是0,因为不用再分割了。实现的时候这里错了。
public class Solution { public int minCut(String s) { int len = s.length(); boolean[][] valid = new boolean[len][len]; // 0-len-1 for (int L = 0; L < len; L++) // L: j-i { for (int i = 0; i < len; i++) { if (L+i>=len) continue; if (L==0) valid[i][i] = true; else if (L==1) valid[i][i+L] = s.charAt(i)==s.charAt(i+L); else { valid[i][i+L] = s.charAt(i)==s.charAt(i+L) && valid[i+1][i+L-1]; } } } int[] cut = new int[len]; // the cuts for 0 to i cut[0] = 0; for (int i = 1; i < len; i++) { if (valid[0][i]) cut[i] = 0; else { cut[i] = Integer.MAX_VALUE; for (int j = 0; j < i; j++) { if (valid[j+1][i] && cut[j]+1 < cut[i]) cut[i] = cut[j]+1; } } } return cut[len-1]; } }