资讯专栏INFORMATION COLUMN

[Leetcode] Longest Palindromic Substring 最长回文子字符串

KnewOne / 1531人阅读

摘要:这种解法中,外层循环遍历的是子字符串的中心点,内层循环则是从中心扩散,一旦不是回文就不再计算其他以此为中心的较大的字符串。

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, and there exists one unique longest palindromic substring.
暴力法 Brute Force 复杂度

时间 O(n^3) 空间 O(1)

思路

暴力法就是穷举所有子字符串的可能,然后依次按位判断其是否是回文,并更新结果。虽然其时间复杂度很高,但它对空间的要求很低。

代码
public class Solution {
    public String longestPalindrome(String s) {
        int maxLength = 0;
        int maxStart = 0;
        int len = s.length();
        //i是字符串长度
        for(int i = 0; i < len; i++){
            //j是字符串起始位置
            for(int j = 0; j < len - i; j++){
                //挨个判断是否回文
                if(isPalindrome(s,i,j) && (i+1)>maxLength){
                    maxLength = i + 1;
                    maxStart = j;
                }
            }
        }
        return s.substring(maxStart,maxStart + maxLength);
    }
    
    private isPalindrome(String s, int i, int j){
        int left = j;
        int right = j + i;
        while(left
动态规划 Dynamic Programming
复杂度

时间 O(n^2) 空间 O(n^2)

思路

根据回文的特性,一个大回文按比例缩小后的字符串也必定是回文,比如ABCCBA,那BCCB肯定也是回文。所以我们可以根据动态规划的两个特点:第一大问题拆解为小问题,第二重复利用之前的计算结果,来解答这道题。那如何划分小问题呢,我们可以先把所有长度最短为1的子字符串计算出来,根据起始位置从左向右,这些必定是回文。然后计算所有长度为2的子字符串,再根据起始位置从左向右。到长度为3的时候,我们就可以利用上次的计算结果:如果中心对称的短字符串不是回文,那长字符串也不是,如果短字符串是回文,那就要看长字符串两头是否一样。这样,一直到长度最大的子字符串,我们就把整个字符串集穷举完了,但是由于使用动态规划,使计算时间从O(N^3)减少到O(n^2)。

注意

外循环的变量控制的实际上不是字符串长度,而是字符串首到尾的增量

二维数组的第一维是指子字符串起始位置,第二维是指终止位置,所存数据表示是否回文

代码
public class Solution {
    public String longestPalindrome(String s) {
        int maxLength = 0;
        int maxStart = 0;
        int len = s.length();
        boolean[][] dp = new boolean[len][len];
        //i是字符串长度
        for(int i = 0; i < len; i++){
            //j是字符串起始位置
            for(int j = 0; j < len - i; j++){
                if(i==0||i==1){
                    //如果字符串长度为0,必定为回文
                    dp[j][j+i] = true;
                } else if(s.charAt(j+i)==s.charAt(j)){
                    //如果左右两端相等,那只要中心对称子字符串是回文就是回文
                    dp[j][j+i] = dp[j+1][j+i-1];
                } else {
                    //否则不是回文
                    dp[j][j+i] = false;
                }
                if(dp[j][j+i] && i > maxLength){
                    maxLength = i + 1;
                    maxStart = j;
                }
            }
        }
        return s.substring(maxStart,maxStart + maxLength);
    }
}
中心扩散法 Spread From Center 复杂度

时间 O(n^2) 空间 O(1)

思路

动态规划虽然优化了时间,但也浪费了空间。实际上我们并不需要一直存储所有子字符串的回文情况,我们需要知道的只是中心对称的较小一层是否是回文。所以如果我们从小到大连续以某点为个中心的所有子字符串进行计算,就能省略这个空间。 这种解法中,外层循环遍历的是子字符串的中心点,内层循环则是从中心扩散,一旦不是回文就不再计算其他以此为中心的较大的字符串。由于中心对称有两种情况,一是奇数个字母以某个字母对称,而是偶数个字母以两个字母中间为对称,所以我们要分别计算这两种对称情况。

代码
public class Solution {
    String longest = "";
    
    public String longestPalindrome(String s) {
        for(int i = 0; i < s.length(); i++){
            //计算奇数子字符串
            helper(s, i, 0);
            //计算偶数子字符串
            helper(s, i, 1);
        }
        return longest;
    }
    
    private void helper(String s, int idx, int offset){
        int left = idx;
        int right = idx + offset;
        while(left>=0 && right longest.length()){
            longest = currLongest;
        }
    }
}

2018/2

class Solution:
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        maxStr = ""
        for index in range(0, len(s)):
            sub1 = self.spreadFromCenter(s, index, 0)
            sub2 = self.spreadFromCenter(s, index, 1)
            if len(sub1) > len(maxStr):
                maxStr = sub1
            if len(sub2) > len(maxStr):
                maxStr = sub2
        return maxStr
        
    def spreadFromCenter(self, string, centerIndex, offset):
        leftIndex = centerIndex
        rightIndex = centerIndex + offset
        length = len(string)
        while leftIndex >= 0 and rightIndex < length and string[leftIndex] == string[rightIndex]:
            leftIndex = leftIndex - 1
            rightIndex = rightIndex + 1
        leftIndex = leftIndex + 1
        substring = string[leftIndex:rightIndex]
        return substring
马拉车算法 Manacher Algorithm 复杂度

时间 O(n) 空间 O(n)

关于时间复杂度的证明:http://www.zhihu.com/question...

思路

Manacher算法是非常经典的计算连续下标回文的算法。它利用了回文的对称性,更具体的来说,是回文内回文的对称性,来解决这个问题。
参见:http://www.felix021.com/blog/...

代码
public class Solution {
    public String longestPalindrome(String s) {
        if(s.length()<=1){
            return s;
        }
        // 预处理字符串,避免奇偶问题
        String str = preProcess(s);
        // idx是当前能够向右延伸的最远的回文串中心点,随着迭代而更新
        // max是当前最长回文串在总字符串中所能延伸到的最右端的位置
        // maxIdx是当前已知的最长回文串中心点
        // maxSpan是当前已知的最长回文串向左或向右能延伸的长度
        int idx = 0, max = 0;
        int maxIdx = 0;
        int maxSpan = 0;
        int[] p = new int[str.length()];
        for(int curr = 1; curr < str.length(); curr++){
            // 找出当前下标相对于idx的对称点
            int symmetryOfCurr = 2 * idx - curr;
            // 如果当前已知延伸的最右端大于当前下标,我们可以用对称点的P值,否则记为1等待检查
            p[curr] = max > curr? Math.min(p[symmetryOfCurr], max - curr):1;
            // 检查并更新当前下标为中心的回文串最远延伸的长度
            while((curr+p[curr])max){
                max = p[curr] + curr;
                idx = curr;
            }
            // 检查并更新当前已知的最长回文串信息
            if(p[curr]>maxSpan){
                maxSpan = p[curr];
                maxIdx = curr;
            }
        }
        //去除占位符
        return s.substring((maxIdx-maxSpan)/2,(maxSpan+maxIdx)/2-1);
    }
    
    private String preProcess(String s){
        // 如ABC,变为$#A#B#C#
        StringBuilder sb = new StringBuilder();
        sb.append("$");
        for(int i = 0; i < s.length(); i++){
            sb.append("#");
            sb.append(s.charAt(i));
        }
        sb.append("#");
        return sb.toString();
    }
}
后续 Follow Up

Q:如果只能在头或尾删,问最少删多少字符能使得该字符串变为回文?
A:就是找到最长回文串,然后把长度减一下就行了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64389.html

相关文章

  • Leetcode 5 Longest Palindromic Substring 最长回文

    摘要:难度题目是说给出一个字符串求出这个字符串的最长回文的子串回文是指前后完全对称的字符串像是之类的都算是回文奇数字母的回文和偶数字母的回文中心是不一样的奇数字母比如的中心在中间字母上偶数字母比如的回文在中间两字母的中心上由此可见回文中心点实际上 Given a string s, find the longest palindromic substring in s. You may as...

    NotFound 评论0 收藏0
  • LeetCode.5 最长回文串(longest-palindromic-substring)(J

    摘要:一题目最长回文子串给定一个字符串,找到中最长的回文子串。你可以假设的最大长度为。示例输入输出注意也是一个有效答案。 一、题目 最长回文子串: 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1: 输入: babad输出: bab注意: aba 也是一个有效答案。 示例 2: 输入: cbbd输出: bb 二、我的答案 思路 1.排...

    Steven 评论0 收藏0
  • LeetCode——Longest Palindromic Substring

    摘要:题目即求最长回文子序列原题链接此篇博客仅为学习记录我的解法及代码暴力解决,用及进行两层遍历循环中套一层循环,用遍历,求最长回文序列字符串,同时用变量记录最长子序列这种写法很暴力,效率很低,一层循环,一层循环,回文序列对比一层,时间复杂度为辣 题目: Given a string s, find the longest palindromic substring in s. You ma...

    shevy 评论0 收藏0
  • LeetCode-5 Longest Palindromic Substring

    摘要:题目解析题目是要找出最长的回文字符串,拿到题目的第一反应是遍历子串,然后一直替换最长的子字符串即可了。但是这种解法遇到极端输入状况就会超时,指定的最长长度为,遍历子串需要两次循环,判断回文需要一次循环,所以总的效率为,那么极端状况会超时。 题目 Given a string s, find the longest palindromic substring in s. You may ...

    psychola 评论0 收藏0
  • leetcode 5 Longest Palindromic Substring Java &

    摘要:回文的意思就是反转字符串后和原字符串相等。因为这种想法没次都是两边同时扩展。所以要分目标字符串长度为奇数目标字符串为偶数两种情况。 题目详情 Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.题目的意思是输入...

    JessYanCoding 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<