zoukankan      html  css  js  c++  java
  • [LeetCode] 5. Longest Palindromic Substring 最长回文子串

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

    Example 1:

    Input: "babad"
    Output: "bab"
    Note: "aba" is also a valid answer.
    

    Example 2:

    Input: "cbbd"
    Output: "bb"

     最长回文子串Longest palindromic substring, 最长回文子串或最长对称因子问题是在一个字符串中查找一个最长连续子串,这个子串必须是回文。例如“banana”最长回文子串是“anana”。最长回文子串算法不应当与最长回文子序列算法混淆。

    解法1: 枚举(enumerate): 基于中心点枚举的算法, 遍历数组,以其中的1个元素或者2个元素作为palindrome的中心,通过辅助函数,寻找能拓展得到的最长子字符串。外层循环 O(n),内层循环O(n),因此时间复杂度 Time O(n^2),因为只需要存最长palindrome子字符串本身,空间更优化:Space O(1)

    解法2:动态归化(DP):

    State: dp[i][j], s[i]到s[j]是否构成一个回文

    Function: dp[i][j] = s[i] == s[j] &&(j - i <= 2 || dp[i + 1][j - 1])

    Initialize: dp[i][j] = true when j - i <= 2

    Return: longest substring: longest = s[i, j + 1]

    解法3:Manacher's Algorithm,可以达到 O(n) 的线性时间复杂度。

    Manacher算法可参考:

    Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串    

    Longest Palindromic Substring Part II

    解法4: 以任意一个字符i为中心点,向两边扩展,直到不是回文为止,计算长度,保留最大长度的字符串。扩展的时候分为奇数和偶数两种情况。

    Java: 

    public class Solution {
        private int lo, maxLen;
    
        public String longestPalindrome(String s) {
            int len = s.length();
            if (len < 2)
                return s;
    
            for (int i = 0; i < len-1; i++) {
                extendPalindrome(s, i, i);  //assume odd length, try to extend Palindrome as possible
                extendPalindrome(s, i, i+1); //assume even length.
            }
            return s.substring(lo, lo + maxLen);
        }
    
        private void extendPalindrome(String s, int j, int k) {
            while (j >= 0 && k < s.length() && s.charAt(j) == s.charAt(k)) {
                j--;
                k++;
            }
            if (maxLen < k - j - 1) {
                lo = j + 1;
                maxLen = k - j - 1;
            }
        }
    }  

    Java: 枚举(enumerate), Time: O(n^2), Space: O(1)

    public class Solution {
        public String longestPalindrome(String s) {
            if (s == null || s.length() == 0) {
                return "";
            }
            
            int start = 0, len = 0, longest = 0;
            for (int i = 0; i < s.length(); i++) {
                len = findLongestPalindromeFrom(s, i, i);
                if (len > longest) {
                    longest = len;
                    start = i - len / 2;
                }
                
                len = findLongestPalindromeFrom(s, i, i + 1);
                if (len > longest) {
                    longest = len;
                    start = i - len / 2 + 1;
                }
            }
            
            return s.substring(start, start + longest);
        }
        
        private int findLongestPalindromeFrom(String s, int left, int right) {
            int len = 0;
            while (left >= 0 && right < s.length()) {
                if (s.charAt(left) != s.charAt(right)) {
                    break;
                }
                len += left == right ? 1 : 2;
                left--;
                right++;
            }
            
            return len;
        }
    }
    

    Java: DP, Time: O(n^2), Space: O(n^2)

    public class Solution {
        public String longestPalindrome(String s) {
            if (s == null || s.length() == 0) {
                return "";
            }
            
            int n = s.length();
            boolean[][] isPalindrome = new boolean[n][n];
            
            int longest = 1, start = 0;
            for (int i = 0; i < n; i++) {
                isPalindrome[i][i] = true;
            }
            for (int i = 0; i < n - 1; i++) {
                isPalindrome[i][i + 1] = s.charAt(i) == s.charAt(i + 1);
                if (isPalindrome[i][i + 1]) {
                    start = i;
                    longest = 2;
                }
            }
            
            for (int i = n - 1; i >= 0; i--) {
                for (int j = i + 2; j < n; j++) {
                    isPalindrome[i][j] = isPalindrome[i + 1][j - 1] && 
                        s.charAt(i) == s.charAt(j);
                        
                    if (isPalindrome[i][j] && j - i + 1 > longest) {
                        start = i;
                        longest = j - i + 1;
                    }
                }
            }
            
            return s.substring(start, start + longest);
        }
    }
    

    Java: Manacher's Algorithm, Time: O(n), Space: O(n)

    public class Solution {
        public String longestPalindrome(String s) {
            if (s == null || s.length() == 0) {
                return "";
            }
            
            // abc => #a#b#c#
            String str = generateString(s);
            
            int[] palindrome = new int[str.length()];
            int mid = 0, longest = 1;
            palindrome[0] = 1;
            for (int i = 1; i < str.length(); i++) {
                int len = 1; 
                if (mid + longest > i) {
                    int mirrorOfI = mid - (i - mid);
                    len = Math.min(palindrome[mirrorOfI], mid + longest - i);
                }
                
                while (i + len < str.length() && i - len >= 0) {
                    if (str.charAt(i - len) != str.charAt(i + len)) {
                        break;
                    }
                    len++;
                }
                
                if (len > longest) {
                    longest = len;
                    mid = i;
                }
                
                palindrome[i] = len;
            }
            
            longest = longest - 1; // remove the extra #
            int start = (mid - 1) / 2 - (longest - 1) / 2;
            return s.substring(start, start + longest);
        }
        
        private String generateString(String s) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.length(); i++) {
                sb.append('#');
                sb.append(s.charAt(i));
            }
            sb.append('#');
            
            return sb.toString();
        }
    }

    Python:

    class Solution(object):
        def longestPalindrome(self, s):
            """
            :type s: str
            :rtype: str
            """
            res = ""
            for i in xrange(len(s)):
                # odd case, like "aba"
                tmp = self.helper(s, i, i)
                if len(tmp) > len(res):
                    res = tmp
                # even case, like "abba"
                tmp = self.helper(s, i, i+1)
                if len(tmp) > len(res):
                    res = tmp
            return res
    
        # get the longest palindrome, l, r are the middle indexes   
        # from inner to outer
        def helper(self, s, l, r):
            while l >= 0 and r < len(s) and s[l] == s[r]:
                l -= 1; r += 1
            return s[l+1:r]    

    Python:

    # Manacher's Algorithm
    class Solution(object):
        def longestPalindrome(self, s):
            """
            :type s: str
            :rtype: str
            """
            def preProcess(s):
                if not s:
                    return ['^', '$']
                T = ['^']
                for c in s:
                    T +=  ['#', c]
                T += ['#', '$']
                return T
    
            T = preProcess(s)
            P = [0] * len(T)
            center, right = 0, 0
            for i in xrange(1, len(T) - 1):
                i_mirror = 2 * center - i
                if right > i:
                    P[i] = min(right - i, P[i_mirror])
                else:
                    P[i] = 0
    
                while T[i + 1 + P[i]] == T[i - 1 - P[i]]:
                    P[i] += 1
    
                if i + P[i] > right:
                    center, right = i, i + P[i]
    
            max_i = 0
            for i in xrange(1, len(T) - 1):
                if P[i] > P[max_i]:
                    max_i = i
            start = (max_i - 1 - P[max_i]) / 2
            return s[start : start + P[max_i]]
    

    C++:

    class Solution {
    public:
        string longestPalindrome(string s) {
            if (s.empty()) return "";
            if (s.size() == 1) return s;
            int min_start = 0, max_len = 1;
            for (int i = 0; i < s.size();) {
              if (s.size() - i <= max_len / 2) break;
              int j = i, k = i;
              while (k < s.size()-1 && s[k+1] == s[k]) ++k; // Skip duplicate characters.
              i = k+1;
              while (k < s.size()-1 && j > 0 && s[k + 1] == s[j - 1]) { ++k; --j; } // Expand.
              int new_len = k - j + 1;
              if (new_len > max_len) { min_start = j; max_len = new_len; }
            }
            return s.substr(min_start, max_len);
        }
    }; 

    类似题目:

    [LeetCode] 125. Valid Palindrome 有效回文

    [LeetCode] 9. Palindrome Number 验证回文数字

    [LeetCode] 516. Longest Palindromic Subsequence 最长回文子序列

    [LeetCode] 647. Palindromic Substrings 回文子字符串

     

    All LeetCode Questions List 题目汇总

      

  • 相关阅读:
    30.过滤掉smb.conf配置文件中的空行和注释行和空白行(初级写法很不严谨)
    29. 分析文件内容,判断 fgets 共执行了多少次?
    28. 使用fgetc()/fputc()实现文件的加密与解密,存在溢出风险。
    27.读文件时通过两种方式判断文件结尾
    26. 使用fgetc()/fputc()实现文件的拷贝
    24. 练习定义几种指针及数组
    23. 实现 func()函数,在func()中,通过操作arr,实现修改str1到str2字符串,并打印所有字符串,考察对指针与数组与字符串的基本掌握
    Windows程序设计(Charles Petzold)HELLOWIN程序实现
    jvm 解释器和JIT编译器
    java 创建线程的方法
  • 原文地址:https://www.cnblogs.com/lightwindy/p/8488346.html
Copyright © 2011-2022 走看看