Leetcode[字串] 5. 最長迴文子串

kev_gogo發表於2020-11-13

Leetcode[字串] 5. 最長迴文子串

審題

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為 1000。

示例 1:

輸入: "babad"
輸出: "bab"
注意: "aba" 也是一個有效答案。

示例 2:

輸入: "cbbd"
輸出: "bb"

我最開始感覺這道題乍一看有些懵,腦海裡能想到的演算法就是 O ( n 2 ) O(n^2) O(n2)的暴力解法,還嫌演算法複雜度太高,但是事實上暴力搜尋的複雜度是要達到 O ( n 3 ) O(n^3) O(n3)的,也就是說左邊界,右邊界和子串的計算移動都是與 n n n有關的。那麼苦思冥想30min後依舊沒想明白,看到了題解才發現一個早有耳聞但是從未了解過的老朋友:動態規劃

那麼這道題為什麼要用動態規劃來解呢?首先就是這個題的形式就很動規,它一個迴文子串的子串一定是迴文子串,因此這可以用劃分子問題的思想進行解答。

程式碼實現

在確定了動態規劃的實現方法以後,我們就有了一個關係,即對於字串 s [ i , j ] s[i,j] s[i,j]即從第 i i i個位置到第 j j j個位置的字串(包含頭尾),我們知道如果 s [ i , j ] s[i,j] s[i,j]是迴文子串,那麼 s [ i + 1 , j − 1 ] s[i+1,j-1] s[i+1,j1]一定也是迴文子串,並且 s [ i ] s[i] s[i]要等於 s [ j ] s[j] s[j]。自此我們有了第一個關係。

有兩個地方需要格外注意一下:

  1. 特判:當字元字串的長度為0或者為1的時候, i + 1 i+1 i+1是小於 j − 1 j-1 j1的,因此需要增加兩個特判,對於 l = 0 l=0 l=0的情況,dp必得1,對於 l = 1 l=1 l=1的情況,如果 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j],也有dp=1,否則dp=0。

  2. 邊界條件的判斷:因為我們是自底向上進行狀態的轉移的,因此外迴圈的字串長度要從小到大。而內迴圈中因為有 i + l i+l i+l這一項,我們的內迴圈終止條件就是 i + l < n i+l<n i+l<n

class Solution {
public:
    string longestPalindrome(string s){
        int n = s.size();
        string ans;
        vector< vector<int> > dp(n, vector<int>(n));
        for ( int l=0; l<n; l++ ) {
            for ( int i=0; i+l<n; i++ ) {
                int j = i+l;
                if ( l == 0 ) dp[i][j] = 1;
                else if ( l == 1 ) dp[i][j] = s[i] == s[j];
                else {
                    dp[i][j] = dp[i+1][j-1] && s[i] == s[j];
                }
                if ( dp[i][j] == 1 && l+1 > ans.size() ) ans = s.substr(i, l+1);
            }
        }
        return ans;
    }
};

反思

這道題運用了動態規劃來求解,雖然複雜度還是高了一點,但是思路無疑是我們需要掌握的,動態規劃的題有的很難,但是大套路基本就幾種,因此,想要掌握動態規劃還需要至少10道題的練習。

相關文章