給定字符串 s
, 須要將它分割成一些子串, 使得每一個子串都是迴文串.數組
最少須要分割幾回?spa
樣例 1:code
輸入: "a" 輸出: 0 解釋: "a" 自己就是迴文串, 無需分割
樣例 2:blog
輸入: "aab" 輸出: 1 解釋: 將 "aab" 分割一次, 獲得 "aa" 和 "b", 它們都是迴文串.
這裏咱們最主要的就是如何判斷出指定區間的字符串爲迴文串,咱們能夠從前日後,以每個字符爲基石,讓其往兩邊伸展,而後考慮奇偶性,由於一個迴文串的長度要麼是奇數,要麼是偶數,就這兩種狀況,因此咱們就能夠定住每個中間字符,向外擴展,判斷這個字符串中哪些區間是迴文串,哪些不是。並用一個二維的布爾類型數組記錄每個區間是否爲迴文串,接下來考慮最後一步就很容易了,咱們知道最後一步必定是從第j個位置分割,將第j + 1個字符到最後一個字符劃分爲一個迴文串,當咱們考慮前i個字符的串是否爲迴文串時,咱們就須要從第一個字符遍歷到第i個字符,從中找到最少分割次數並更新。這樣一來咱們就把考慮前i個字符的串最少分割幾回,轉變爲前j個字符的串最少分割幾回。字符串
轉移方程:f[i] = min{f[i], f[j] + 1}string
1 public class Solution { 2 /** 3 * @param s: A string 4 * @return: An integer 5 */ 6 public int minCut(String s) { 7 // write your code here 8 if (s == null || s.length() == 0) { 9 return 0; 10 } 11 12 char[] c = s.toCharArray(); 13 int n = c.length; 14 15 boolean[][] isPalins = new boolean[n][n]; 16 17 // initialization 18 for (int i = 0; i < n; i++) { 19 for (int j = 0; j < n; j++) { 20 isPalins[i][j] = false; 21 } 22 } 23 24 // 定基準 25 for (int t = 0; t < n; t++) { 26 int i, j; 27 // 默認一個字符也是迴文串 28 i = t; 29 j = t; 30 31 // odd 32 while (i >= 0 && j < n && c[i] == c[j]) { 33 isPalins[i][j] = true; 34 i--; 35 j++; 36 } 37 38 i = t; 39 j = t + 1; 40 // even 41 while (i >= 0 && j < n && c[i] == c[j]) { 42 isPalins[i][j] = true; 43 i--; 44 j++; 45 } 46 } 47 48 // 定義狀態:dp[i] 表明前i個字符中迴文串的個數 49 int[] dp = new int[n + 1]; 50 51 // 初始化 52 dp[0] = 0; 53 54 for (int i = 1; i <= n; i++) { 55 // 由於這裏是取最小值,因此一開始要設爲無窮大 56 // 任意一個字符串(空串除外)都能化成若干個迴文串(由於單個字符就是一個迴文串),因此必定能夠分割出來,即這裏設置爲無窮大也就沒啥問題 57 dp[i] = Integer.MAX_VALUE; 58 // 從第一個字符一直遍歷到第i個字符。挨個判斷,取最小值 59 for (int j = 0; j < i; j++) { 60 if (isPalins[j][i - 1]) { 61 // is Palin 62 dp[i] = Math.min(dp[i], dp[j] + 1); 63 } 64 } 65 } 66 67 // 別忘了本題是讓咱們求最小須要分割幾回,全部最後要-1 68 return dp[n] - 1; 69 } 70 }