題目
給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。
示例 1:輸入: “ABCDDCEFA”。輸出: “CDDC”。
迴文子串就是一個字串從左到右讀和從右到左讀是完全一樣的,比如 “a”、“aba”、“abba”。
條件
字串:ABCDDCEFA
動態規劃問題建模階段
i是終止字元,j是起始字元
i結束\j開始 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | 1 | ||||||||
1 | 0 | 1 | |||||||
2 | 0 | 0 | 1 | ||||||
3 | 0 | 0 | 0 | 1 | |||||
4 | 0 | 0 | 0 | 1 | 1 | ||||
5 | 0 | 0 | 1 | 0 | 0 | 1 | |||
6 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ||
7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |
8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
規律:
d[0][0] = 1
d[4][3] = 1 表示字串從str[3]到str[4] = DD
d[5][2] = 1 表示字串從str[2]到str[5] = CDDC
由此可見,當子串兩端的字元str[i]=str[j]時,再判斷去掉兩端字元的子串d[i-1][j+1]是否是迴文。
如果是迴文,即d[i-1][j+1]=1,則d[i][j]是迴文
動態規劃三個重要的概念
最優子結構:
當str[8]=str[0]時,判斷d[1][7],即從str[1]到str[7]是否是迴文
邊界:
d[0][0] = 1
轉態轉移公式:
d[i][j] = 1 , i-j<3, str[i]=str[j] 因為小於3個字元一定是迴文,例 A、AA、ABA
d[i][j] = d[i-1][j+1] , i-j>3, str[i]=str[j]
動態規劃求解問題階段
<?php
namespace app\index\controller;
// 動態規劃求解問題階段:
class Index
{
/**
* 動態規劃(Dynamic Programming)
* 時間複雜度:O(n²)
* 空間複雜度:O(n²)
*/
public function test()
{
$str = 'babad';
$palindrome = []; // 儲存“起始字元到終止字元”是否是迴文,1是,0否
$max_len = 1; // 儲存最長迴文子串長度
$start_char = 0; // 儲存最長迴文子串的起始位置
$str_len = strlen($str);
// 迴圈字串, i是終止字元
for ($i=0; $i<$str_len;$i++) {
// 迴圈i終止字元的每種長度情況,j是起始字元
for ($j=0;$j<$i;$j++) {
// 先賦初始值,供後面判斷 $max_len 時使用
$palindrome[$i][$j] = 0;
// 字串兩頭相等,根據三種情況判斷是否為迴文
if ($str[$i] == $str[$j]) {
// 情況一:如果只有一個字元:i-j = 0;(例 A) 在陣列對角線,值全為1,可寫可不寫
// 情況二:如果有兩個字元: i-j = 1;(例 AA)
// 情況三:如果有三個字元: i-j = 2;(例 ABA)
// 這三種情況都為迴文
if ($i-$j < 3) {
$palindrome[$i][$j] = 1;
} else {
// 情況四:如果子串長度大於3,則判斷 $palindrome[i-1][j+1] 是否為1。(去兩端的字串)
if ($palindrome[$i-1][$j+1]) {
$palindrome[$i][$j] = 1;
}
}
// 如果是迴文,且其長度比$max_len大,則更新$max_len值
if ($i-$j+1>$max_len && $palindrome[$i][$j]) {
$max_len = $i-$j+1;
$start_char = $j;
}
}
}
}
echo $max_len . "</br>";
echo $start_char;
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結