[動態規劃] 六、最長迴文子串

ajiang02發表於2020-02-20

題目

給定一個字串 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 協議》,轉載必須註明作者和本文連結

相關文章