LeetCode-Python/Java-647. 回文子列

3959 ワード

文字列を指定すると、この文字列に何個の返信サブ列があるかを計算します.
異なる開始位置または終了位置を持つサブストリングは、同じ文字で構成されていても異なるサブストリングとしてカウントされます.
例1:
  : "abc"
  : 3
  :       : "a", "b", "c".

例2:
  : "aaa"
  : 6
  : 6     : "a", "a", "a", "aa", "aa", "aaa".

注意:
  • 入力文字列の長さは1000を超えません.

  • 第一の考え方:
    暴力解、すべての子串を探し出して、更に一つ一つ文串かどうかを判断します.
    class Solution(object):
        def countSubstrings(self, s):
            """
            :type s: str
            :rtype: int
            """
            res = 0
            for i in range(len(s)):
                for j in range(1, len(s) + 1 - i):
                    tmp = s[i:i + j]
                    if tmp == tmp[::-1]:
                        res += 1
                        
            return res
    class Solution {
        public int countSubstrings(String s) {
            int n = s.length(), cnt = 0;
            for (int i = 0; i < n; i++)
                for (int j = i; j < n; j++){
                    boolean equals = true;
                    int ni = i, nj = j;
                    while(ni <= nj){
                        if (s.charAt(ni++) != s.charAt(nj--)){
                            equals = false;
                            break;
                        }
                    }
                    if (equals)
                        cnt++;
                }
            return cnt;
        }
    }

    2つ目の考え方:
    動的計画では,s[i:j+1]が回文サブ列であるか否かをdp[i][j]で記録し,もしそうであればdp[i][j]=1,そうでなければdp[i][j]=0とする.
    なお、i−j<=1であれば、サブストリング長が0または1であることを示すので、dp[i−1][j+1]を考慮する必要はない.
    class Solution(object):
        def countSubstrings(self, s):
            """
            :type s: str
            :rtype: int
            """
            #dp[i][j]   s[i:j+1]       
            dp = [[0 for i in range(len(s))] for j in range(len(s))]
            res = 0
            for i in range(len(s)):
                for j in range(i, -1, -1):
                    if s[i] == s[j] and (i - j <= 1 or dp[i - 1][j + 1]): # i - j<=1       dp[i-1][j+1]
                        dp[i][j] = 1
                        res += 1
            return res
    class Solution {
        public int countSubstrings(String s) {
            int n = s.length(), cnt = 0;
            boolean[][] dp = new boolean[n][n];
            for (int i = 0; i < n; i++)
                for (int j = i; j >= 0; j--){
                    if (s.charAt(i) == s.charAt(j) && (i - j <= 1 || dp[i - 1][j + 1])){
                        dp[i][j] = true;
                        cnt++;
                    }
                }
            return cnt;
            
        }
    }

    3つ目の考え方:
    中心拡散法は、長さ1のサブストリングを中心として両側に拡散する、
    s[i]を中心としたサブストリングとs[i],s[i+1]を中心としたサブストリングが回文サブストリングであるか否かをそれぞれ判断する.
    class Solution(object):
        def countSubstrings(self, s):
            """
            :type s: str
            :rtype: int
            """
            self.res = 0
            
            def extend(left, right):
                for i in range(len(s)):
                    while(left >= 0 and right < len(s) and s[left] == s[right]):
                        self.res += 1
                        left -= 1
                        right += 1
                        
            for i in range(len(s)):
                extend(i, i)
                extend(i, i+1)
            
            return self.res
    class Solution {
        private int cnt = 0;
        
        public int countSubstrings(String s) {
            for (int i = 0; i< s.length(); i ++){
                check(s, i, i);
                check(s, i, i + 1);
            }    
            return cnt;
        }
        
        public void check(String s, int start, int end){
            while(start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){
                cnt++;
                start--;
                end++;
            }
        }
    }