LeetCode5.最长回文子串

题目:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
输入: "cbbd"
输出: "bb"

思路:

  1. 背向双指针,遍历每一个索引,以这个索引为中心,利用“回文串”中心对称的特点,往两边扩散,看最多能扩散多远。
    • 奇数回文串的“中心”是一个具体的字符,例如:回文串 “aba” 的中心是字符 “b”;
    • 偶数回文串的“中心”是位于中间的两个字符的“空隙”,例如:回文串串 “abba” 的中心是两个 “b” 中间的那个“空隙”。
      在这里插入图片描述
      注意: String.substring(beginIndex, endIndex)返回一个新字符串,它是此字符串的一个子字符串。该子字符串从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。因此,该子字符串的长度为 endIndex-beginIndex。
  2. Manancher’s Algorithm,有点复杂,据说面试不考,还没有看懂。

代码:

  1. 背向双指针
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) {
        	//对于奇数长度的字符串,中心为一个数,左右起点都是i
            len = findLongestPalindrome(s, i, i);
            if (len > longest) {
                longest = len;
                start = i - len / 2;
            }

			//对于偶数长度的字符串,中心是两数之间,左右起点不一样
            len = findLongestPalindrome(s, i, i + 1);
            if (len > longest) {
                longest = len;
                start = i - len / 2 + 1;
            }
        }
        return s.substring(start, start + longest);
    }

	//找到指定了左右起点往两边扩散的最长回文子串长度
    public int findLongestPalindrome(String s, int left, int right) {
        int len = 0;
        while (left >= 0 && right < s.length()) {
        	//如果左右扩散的两个值不一样,则说明已经不是回文串
            if (s.charAt(left) != s.charAt(right)) {
                break;
            }

			//左右起点归一时长度只增加1,否则加2
            len += (left == right ? 1 : 2);
            left--;
            right++;
        }
        return len;
    }
}
  1. 使用 Manancher’s Algorithm,可以在 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();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值