1. 程式人生 > >LeetCode 647. Palindromic Substrings (迴文子字串)

LeetCode 647. Palindromic Substrings (迴文子字串)

原題

Given a string, your task is to count how many palindromic substrings in this string.

The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.

Example 1:

Input: "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".

Example 2:

Input: "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".

Note:

  1. The input string length won’t exceed 1000.

Reference Answer

Method one

暴力迴圈
看到字元的長度只有1000,首先用暴力解法。雙重迴圈,得到所有的子字串,然後判斷是不是迴文。

時間複雜度基本是O(N^3),超過1%的提交。

這裡的s[i:j+1]是沒有問題的,因為j

最多取到len(s) - 1,則 j+1 最多取到len(s),而s又取不到 j+1

Code

class Solution(object):
    def countSubstrings(self, s):
        """
        :type s: str
        :rtype: int
        """
        count = 0
        for i in xrange(len(s)):
            for j in xrange(i, len(s)):
                if s[i:j + 1] ==
s[i:j + 1][::-1]: count += 1 return count

Method Two

固定起點向後找

index從0到len進行遍歷。對於每個單個的字元,其本身是一個迴文。然後對迴文長度是奇數的情況進行遍歷:使用left和right雙指標,往兩邊走,判斷總長度是3,5,7……的子串是不是迴文(left指標和right指標指向的字元相等)。再對迴文是偶數的情況同樣的進行遍歷。最後求和即可。

比較巧妙的一種思想,不要怕程式碼長,其實沒啥。

class Solution(object):
    def countSubstrings(self, s):
        """
        :type s: str
        :rtype: int
        """
        count = 0
        for i in xrange(len(s)):
            count += 1
            #迴文長度是奇數的情況
            left = i - 1
            right = i + 1
            while left >= 0 and right < len(s) and s[left] == s[right]:
                count += 1
                left -= 1
                right += 1
            #迴文長度是偶數的情況
            left = i
            right = i + 1
            while left >= 0 and right < len(s) and s[left] == s[right]:
                count += 1
                left -= 1
                right += 1
        return count

Method Three

動態規劃:

動態規劃的思想是,我們先確定所有的迴文,即 string[start:end]是迴文. 當我們要確定string[i:j] 是不是迴文的時候,要確定:

  1. string[i] 等於 string[j]嗎?
  2. string[i+1:j-1]是迴文嗎?

單個字元是迴文;兩個連續字元如果相等是迴文;如果有3個以上的字元,需要兩頭相等並且去掉首尾之後依然是迴文。

這道題想到了用DP,但是DP的規律沒想到,如參考答案所示,需要根據子字串長度進行分別判定,程式碼l == 1 or (l == 2 and s[i] == s[j]) or (l >= 3 and s[i] == s[j] and dp[i + 1][j - 1])正是對應了長度為1、2以及3及3以上三種狀態判定方式。
dp設定為二維False陣列,主要判定依據為(l >= 3 and s[i] == s[j] and dp[i + 1][j - 1])

Python程式碼如下:

class Solution(object):
    def countSubstrings(self, s):
        """
        :type s: str
        :rtype: int
        """
        count = 0
        N = len(s)
        dp = [[False] * N for _ in range(N)]
        for l in range(1, N + 1): # step size
            for i in range(N - l + 1):
                j = i + l - 1
                if l == 1 or (l == 2 and s[i] == s[j]) or (l >= 3 and s[i] == s[j] and dp[i + 1][j - 1]):
                    dp[i][j] = True
                    count += 1
        return count

C++ Version:

class Solution {
public:
    int countSubstrings(string s) {
        const int N = s.size();
        vector<vector<int>> dp(N, vector<int>(N, false));
        int count = 0;
        for (int l = 1; l <= N; l ++) {
            for (int i = 0; i <= N - l; i ++) {
                int j = i + l - 1;
                if (l == 1 || (l == 2 && s[i] == s[j]) || (l >= 3 && s[i] == s[j] && dp[i + 1][j - 1])) {
                    count ++;
                    dp[i][j] = true;
                }
            }
        }
        return count;
    }
};

Note

  • 暴力索引首先應該想到的,而dp方法的規律還是需要經驗鍛鍊。

參考文獻

[1] https://blog.csdn.net/fuxuemingzhu/article/details/79433960