動機

的確是dp,但也可以不用dp… 好像只要是回文都可以用列舉中央去解

Problem

Given a string s, return the longest palindromic substring in s.

 

Example 1:

Input: s = babadOutput: babNote: aba is also a valid answer.

Example 2:

Input: s = cbbdOutput: bb

Example 3:

Input: s = aOutput: a

Example 4:

Input: s = acOutput: a

 

Constraints:

  • 1 <= s.length <= 1000
  • s consist of only digits and English letters.

Ver1: TLE

定義dp[i][j]s[i:j]的回文長度,如果不是回文就是0

所以可以列舉所有可能的子字串,去看

但是要怎麼加速?

通常列舉的資料如果是可以遞迴的或是可以一層一層的疊上去就可以考慮用dp 但就算是列舉的資料如果是可以遞迴的或是可以一層一層的疊上去,如果其內容不與其他答案重疊,就會變成Divide and Conquer

@DP = Array.new(1000) {Array.new(1000,nil)}
def f(s,i,j,dp)
    if !dp[i][j]
        if i >= s.size || j < 0 || i > j
            dp[i][j] = -1
        elsif s[i] == s[j] && i+1 < s.size && j-1 >= 0 && i+1 <= j-1
            ret = f(s,i+1,j-1,dp)
            if ret > 0
                dp[i][j] = 2 + ret
            else
                dp[i][j] = 0
            end
        else
            dp[i][j] = 0
        end
    end
    return dp[i][j]
end
def find_out_continuousSeq(s,dp)
    cc = nil
    acc = 0
    old = 0
    s.each_char.with_index do |c,i|
        if c == cc
            acc += 1
            dp[i-acc][i] = dp[i-acc][i-1] + 1
        else
            acc = 0
        end
        cc = c
    end
end
def longest_palindrome(s)
    #dp = Array.new(s.size){Array.new(s.size,nil)}
    dp = @DP
    dp.map! {|x| x.fill(nil)}
    ans = 0
    str = ""
    (0...s.size).each {|x| dp[x][x] = 1}
    find_out_continuousSeq(s,dp)
    (0...s.size).each do |i|
        break if (s.size-i) < ans
        ((i+ans)...s.size).each do |j|
            f(s,i,j,dp)
            old = ans
            ans = [ans,f(s,i,j,dp)].compact.max
            if ans > old
                i, j = [i,j].sort
                str = s[i..j]
                old = ans
            end
        end
    end
    return str
end

寫到後面才想起,Ruby與Python不能操作巨大的array 十分耗時

如果要的話,就用hash table替代

Ver2: AC

// i~j之間的回文長度,不是回文就是0
int dp[1000][1000] = {-2};
class Solution {
public:
    int f(string &s,int i,int j) {
        if(dp[i][j] == -2) {
            if(i >= s.length() || j < 0 || i > j)
                dp[i][j] = -1;
            else if(s[i] == s[j] && i+1 < s.length() && j-1 >= 0 && i+1 <= j-1) {
                int ret = f(s,i+1,j-1);
                dp[i][j] = ret > 0 ? ret+2 : 0;
            }
            else
                dp[i][j] = 0;
        }
        return dp[i][j];
    }
    void initDP() {
        for(int i=0;i<1000;i++)
            for(int j=0;j<1000;j++)
                dp[i][j] = -2;
        for(int i=0;i<1000;i++)
            dp[i][i] = 1;
    }
    void find_out_continuousSeq(string &s) {
        char cc='-';
        int acc = 0;
        for(int i=0;i<s.length();i++) {
            if(s[i] == cc)
                acc++, dp[i-acc][i] = dp[i-acc][i-1] + 1;
            else
                acc = 0;
            cc = s[i];
        }
        
    }
    string longestPalindrome(string s) {
        int a=0,b=0;
        initDP();
        int ans = 0;
        find_out_continuousSeq(s); //先找出連續的string baaab的aaa
        for(int i=0;i<s.length();i++) {
            if(s.length()-i < ans)
               break;
            
            for(int j=i+ans;j<s.length();j++){
                int old = ans;
                ans = max(ans,f(s,i,j));
                if(ans>old)
                    a=i,b=j,old=ans;
            }
                
        }
        //cout << ans <<','<<a <<','<<b<< '\n';
        return s.substr(a,b-a+1);
    }
};

比較短的DP,但在py會TLE

class Solution:
    def longestPalindrome(self, s: str) -> str:
        @cache
        def isPalin(i,j):
            if j-i < 0:
                return False
            elif j-i == 1 or j-i == 0:
                return True
            else:
                return s[i] == s[j-1] and isPalin(i+1,j-1)
        a,b = 0,0
        for i in range(len(s)):
            for j in range(i+1,len(s)+1):
                if j-i > b-a and isPalin(i,j):
                    a,b=i,j
        return s[a:b]

列舉中央

列舉中央開始擴展回文也是n平方!! 同時這也是py能被AC的解

class Solution:
    def longestPalindrome(self, s: str) -> str:
        def center(a,b):
            while 0 <= a < len(s) and 0 <= b < len(s) and s[a] == s[b]:
                a,b = a-1,b+1
            return [a+1,b]
        x,y = 0,0
        for i in range(len(s)):
            for (a,b) in [center(i,i), center(i-1,i)]:
                if 0 <= a < len(s) and 0 < b <= len(s) and y-x < b-a:
                    x,y=a,b
        return s[x:y]