[leetcode]Longest Palindromic Substring

 此题我曾经做过类似的(http://hi.baidu.com/lautsie/item/459a182eeddc568e6f2cc34a)但还是忘了,可见这个算法还是很tricky的。其实O(n^2)的算法还是能想到的,就是遍历每个字符,然后从该字符向两旁扩,寻找最长子串。但居然有O(n)的方法,见下面链接。

http://www.felix021.com/blog/read.php?2040

最后的代码其实可以做优化,比如最后不需要再遍历一边p[],但复杂度不变,又不是关键,就这样吧~

public class Solution {
    public String longestPalindrome(String s) {
        // Start typing your Java solution below
        // DO NOT write main() function
        StringBuilder sb = new StringBuilder();
        sb.append('#');
        for (int i = 0; i < s.length(); i++)
        {
            sb.append(s.charAt(i));
        	sb.append('#');
        }
        
        String ss = sb.toString();
        int[] p = new int[ss.length()];
        int mx = 0;
        int id = 0;
        for (int i = 0; i < ss.length(); i++)
        {
        	p[i] = mx > i ? Math.min(p[id * 2 -i], mx - i) : 1;
        	while (i+p[i] < ss.length() && i - p[i] >=0)
        	{
        		if (ss.charAt(i + p[i]) == ss.charAt(i-p[i]))
        		{
        			p[i]++;
        		}
        		else
        		{
        			break;
        		}
        	}
        	if (i + p[i] > mx)
        	{
        		mx = i + p[i];
        		id = i;
        	}
        }
        
        // process result
        int maxIndex = 0;
        int maxLen = 0;
        for (int i = 0; i < ss.length(); i++)
        {
        	if( p[i] > maxLen)
        	{
        		maxLen = p[i];
        		maxIndex = i;
        	}
        }
        StringBuilder r = new StringBuilder();
        for (int i = maxIndex - p[maxIndex] + 1; i <= maxIndex + p[maxIndex] - 1; i++)
        {
        	if(ss.charAt(i) != '#')
        	{
        		r.append(ss.charAt(i));
        	}
        }
        return r.toString();
    }
}

第二刷,不强求用Manacher方法。使用n^2的方法,要注意长度为奇数和偶数两种情况。

class Solution {
public:
    string longestPalindrome(string s) {
        int maxLen = 0;
        int idx = 0;
        for (int i = 0; i < s.length(); i++)
        {
            for (int len = 0; i - len >= 0 && i+len < s.length(); len++)
            {
                if (s[i-len] != s[i+len])
                    break;
                if (maxLen < len * 2 + 1)
                {
                    maxLen = len * 2 + 1;
                    idx = i - len;
                }
            }
            for (int len = 0; i - len >= 0 && i+len+1 < s.length(); len++)
            {
                if (s[i-len] != s[i+len+1])
                    break;
                if (maxLen < (len + 1) * 2)
                {
                    maxLen = (len + 1) * 2;
                    idx = i - len;
                }
            }
        }
        return s.substr(idx, maxLen);
    }
};

python3的dp,最后超时了。还是中心扩散法好。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        palindromeDict = {}
        result = ''
        length = 1
        while length <= len(s):
            for idx in range(len(s)):
                if idx + length <= len(s):
                    if length == 1:
                        palindromeDict[(idx, length)] = True
                        if palindromeDict[(idx, length)] and length > len(result):
                            result = s[idx : idx + length]
                    elif length == 2:
                        palindromeDict[(idx, length)] = (s[idx] == s[idx + 1])
                        if palindromeDict[(idx, length)] and length > len(result):
                            result = s[idx : idx + length]
                    else: # length > 2
                        palindromeDict[(idx, length)] = (s[idx] == s[idx + length - 1]) and palindromeDict[(idx + 1, length - 2)]
                        if palindromeDict[(idx, length)] and length > len(result):
                            result = s[idx : idx + length]
                        
            length += 1
            
        return result
        
        

Python3的中心扩散法

class Solution:
    def longestPalindrome(self, s: str) -> str:
        result = ''
        for i in range(len(s) * 2 - 1):
            center = i // 2
            if i % 2 == 1:
                left = center
                right = center + 1
            else: # i % 2 == 0
                left = center
                right = center
            while left >= 0 and right < len(s):
                if s[left] == s[right]:
                    if right - left + 1 > len(result):
                        result = s[left : right + 1]
                    left -= 1
                    right += 1
                else:
                    break
                
            
        return result
        
        

  

原文地址:https://www.cnblogs.com/lautsie/p/3194675.html