【字符串】最长回文子串 ( 动态规划算法 ) ★
文章目錄
- 一、回文串、子串、子序列
- 二、最長回文子串
- 1、動態規劃算法
- 2、動態規劃算法代碼示例
一、回文串、子串、子序列
" 回文串 ( Palindrome ) " 是 正反都一樣的字符串 , abccba , 001100 等字符串 ;
給定一個字符串 " abcd " ,
" 子串 ( SubString ) "是連續取的子字符串 , 如 : “ab” , “bc” , “cd” , “bcd” 等 , 不能跳躍字符 ; ( 連續字符 )
nnn 個字符串的子串個數是 n(n+1)2+1\cfrac{n(n+1)}{2} +12n(n+1)?+1 個 ;
" 子序列 ( SubSequence ) " 是可以非連續取字符串中的字符 , 前后順序不允許顛倒 , 如 “ad” , “bd” , “acd” 等 ; ( 非連續字符 )
nnn 個字符串的子串個數是 2n2^n2n 個 ( 集合的子集數 ) ;
驗證一個字符串是否是回文串 , 最壞的情況下需要遍歷 n2\cfrac{n}{2}2n? 次 ;
因此最暴力的方法驗證回文子串 , 就是驗證 n(n+1)2+1\cfrac{n(n+1)}{2} +12n(n+1)?+1 個子字符串是否是回文串 , 每次都要遍歷 n2\cfrac{n}{2}2n? 次 ;
暴力算法的時間復雜度是 O(n3)O(n^3)O(n3) ;
二、最長回文子串
問題鏈接 : https://www.lintcode.com/problem/200/description
給出一個字符串(假設長度最長為1000),求出它的最長回文子串,你可以假定只有一個滿足條件的最長回文串。
1、動態規劃算法
如果不使用中心線枚舉算法 , 在蠻力算法的基礎上 , 快速判定字符串是否是回文串 ;
使用基于動態規劃的算法可以實現上述要求 ;
回文串存在特點 :
兩種類型的回文串 “abba” , “abcba” , 正序 和 倒序 是一樣的 ;
回文串兩頭的字符相等 ;
回文串除去兩頭的兩個字符 , 中間部分也是回文串 ;
字符串中 iii ~ jjj 之間的字符串是回文串 ;
- 則 i,ji, ji,j 字符相等 ,
- 并且 i+1i +1i+1 ~ j?1j - 1j?1 的字符串也是回文串 ;
iii ~ jjj 之間的字符串是否是回文串 , 依賴于 i+1i +1i+1 ~ j?1j - 1j?1 之間的字符串是否是回文串 ;
因此推導任意兩個索引區間 i,ji, ji,j 之間的字符串是否是回文串時 ,
將 i,ji, ji,j 之間的字符串是否是回文串 , 存儲在一個二維布爾數組中 ;
// 表示 n 個字符串中所有的字符索引之間是否是回文串 boolean [][] isPalindrome = new boolean[n][n];isPalindrome[i][j] 表示 iii ~ jjj 之間的字符串是否是回文串 , 如果是回文串則設置為 true , 如果不是回文串則設置為 false ;
回文串判定條件 :
isPalindrome[i][j] = isPalindrome[i + 1][j - 1] && s.charAt(i) == s.charAt(j);iii ~ jjj 之間的字符串是回文串 , 則 i+1i +1i+1 ~ j?1j - 1j?1 之間的字符串也是回文串 , 并且第 iii 個字符等于第 jjj 個字符 ;
動態規劃 :
這種推導公式在 動態規劃 中 , 稱為 狀態轉移方程 ;
isPalindrome 二維數組中每個元素都是一個 狀態 , 這個狀態是以區間作為狀態的標志 , 兩個維度的值分別是區間的開始索引和結束索引 ;
這種類型的動態規劃 , 又稱為 區間型動態規劃 ;
循環設計 :
iii ~ jjj 之間的字符串是否是回文串 , 依賴于 i+1i +1i+1 ~ j?1j - 1j?1 之間的字符串是否是回文串 ;
也就是 iii 依賴于 i+1i + 1i+1 , 循環時 , 不能正向循環 , 只能倒序循環 ;
先計算 iii 比較大的 , 再計算 iii 比較小的 ;
初始化操作 : 動態規劃中初始化很重要 ;
這里要考慮公式的適用性 , 上述公式
isPalindrome[i][j] = isPalindrome[i + 1][j - 1] && s.charAt(i) == s.charAt(j);公式中使用了 i+1i + 1i+1 , j?1j - 1j?1 , 為了保證公式成立 , 字符串的字符個數至少要有 222 個 ;
初始化時最好將空字符串 , 111 個字符組成的字符串 的情況直接初始化賦值 ;
初始化單個字符字符串的狀態 :
isPalindrome[i][i] 是第 iii 個字符到第 iii 個字符之間的單個字符是否是回文串 , 顯然單個字符是回文串 ;
isPalindrome[i][i] = true2、動態規劃算法代碼示例
代碼示例 :
class Solution {/*** @param s: 輸入字符串* @return: 返回最長回文子串*/public String longestPalindrome(String s) {if (s == null || "".equals(s)) {return null;}int n = s.length();boolean[][] isPalindrome = new boolean[n][n];int longest = 1; // 最長長度int start = 0; // 開始索引// 初始化操作, 長度為 1 的回文串for (int i = 0; i < n; i++) {isPalindrome[i][i] = true;}// 初始化操作, 長度為 2 的回文串for (int i = 0; i < n - 1; i ++) {if (s.charAt(i) == s.charAt(i + 1)) {isPalindrome[i][i + 1] = true;start = i;longest = 2;}else {isPalindrome[i][i + 1] = false;}}// 倒序遍歷for (int i = n - 1; i >= 0; i--) {// 從 i + 2 開始計算 , 之前 i , i + 1 都已經計算過了 , 從長度為 3 的區間開始計算// 注意此處如果 j >= n 時 , 不進入內層循環 // 只有在 j <= n - 1 時 , 才進入內層循環 for (int j = i + 2; j < n; j ++) {isPalindrome[i][j] = isPalindrome[i + 1][j - 1] && s.charAt(i) == s.charAt(j);if (isPalindrome[i][j] && j - i + 1 > longest) {start = i;longest = j - i + 1;}}}return s.substring(start, start + longest);} }class Main {public static void main(String[] args) {String palindrome = new Solution().longestPalindrome("mabcban");System.out.println(palindrome);} }O(n2)O(n^2)O(n2) 時間復雜度算法;
總結
以上是生活随笔為你收集整理的【字符串】最长回文子串 ( 动态规划算法 ) ★的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【错误记录】Google Play 上架
- 下一篇: 【字符串】字符串查找 ( 蛮力算法 )