「程式碼隨想錄演算法訓練營」第四十天 | 動態規劃 part13

云雀AC了一整天發表於2024-08-17

647. 迴文子串

題目連結:https://leetcode.cn/problems/palindromic-substrings/
文章講解:https://programmercarl.com/0647.迴文子串.html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV17G4y1y7z9/
題目狀態:看題解

思路一:動態規劃

使用一個二維動規陣列dp[i][j]來儲存從s[i]s[j](或從s[j]s[i],一樣的,本題程式碼是從j到i)是否屬於迴文子串。兩層遍歷該字串,來記錄迴文子串的個數。

  • s[i] == s[j]時,要判斷一下ij的距離,若i和j的距離為0和1,則表示這是一個迴文子串。
  • s[i] == s[j]時,但ij的距離較大,那麼就要看其裡面的一個是不是迴文子串。

程式碼一:

class Solution {
public:
    int countSubstrings(string s) {
        int len = s.size();
        vector<vector<bool>> dp(len, vector<bool>(len, false));
        int ans = 0;
        for(int i = len - 1; i >= 0; --i) {
            for(int j = i; j < len; ++j) {
                if(s[i] == s[j]) {
                    if(j - i <= 1) {
                        ans++;
                        dp[i][j] = true;
                    } else if(dp[i + 1][j - 1]){
                        ans++;
                        dp[i][j] = true;
                    }
                }
            }
        }
        return ans;
    }
};

思路二:雙指標

使用一個輔助函式extend來遍歷有多少子串,其中i和j分別是兩個起點指標,兩個指標分別向前和向後遍歷,如果遇到i不等於j的時候,就可以返回了,結果就是以i和j為中間點的子串有多少。而在主函式中,兩次呼叫extend函式分別表示奇子串和偶子串。

程式碼二:

class Solution {
public:
    int countSubstrings(string s) {
        int ans = 0;
        for(int i = 0; i < s.size(); ++i) {
            ans += extend(s, i, i, s.size());
            ans += extend(s, i, i + 1, s.size());
        }
        return ans;
    }
    int extend(const string &s, int i, int j, int n) {
        int ans = 0;
        while(i >= 0 && j < n && s[i] == s[j]) {
            i--;
            j++;
            ans++;
        }
        return ans;
    }
};

516. 最長迴文子序列

題目連結:https://leetcode.cn/problems/longest-palindromic-subsequence/
文章講解:https://programmercarl.com/0516.最長迴文子序列.html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV1d8411K7W6/
題目狀態:看題解

思路:

維護一個動規陣列dp[i][j]表示從s[i]s[j]的最長迴文子序列的大小。

  • s[i] == s[j]時,表示其是一個迴文序列,因此將這兩個字元加入進來,即dp[i][j] = dp[i + 1][j - 1] + 2
  • s[i] != s[j]時,我們就需要找在這個範圍裡的最大子序列的個數了。

程式碼:

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int len = s.size();
        vector<vector<int>> dp(len, vector<int>(len, 0));
        for(int i = 0; i < len; ++i) dp[i][i] = 1;
        for(int i = len - 1; i >= 0; --i) {
            for(int j = i + 1; j < len; ++j) {
                if(s[i] == s[j]) dp[i][j] = dp[i + 1][j - 1] + 2;
                else dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
        return dp[0][len - 1];
    }
};

動態規劃總結

image

相關文章