#5 Longest Palindromic Substring

Description

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

Examples

Example1

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

Example2

Input: “cbbd”
Output: “bb”

解题思路

如果要分奇偶情况讨论很麻烦,所以在字符串中每两个字符之间都加上分隔符#,这样无论回文字数是奇数还是偶数都可以统一处理

以题目给出的例子写一下
“babad” -> “#b#a#b#a#d#”

  • 回文子串bab以a作为center,半径为3

“cbbd” -> “#c#b#b#d#”

  • 回文子串bb以#作为center,半径为2

接下来的事情就很简单了,对更新之后的字符串进行遍历,对每个索引点检测以它为center的回文串长度,如果比现有最长的长,就更新max_length和start_pos

java代码如下:

class Solution {
    public String longestPalindrome(String s) {
        int i, j, pos_start = 0, max_len = 0;
        String s_temp = "#";
        for(i = 0; i < s.length(); i++){
            s_temp += s.charAt(i);
            s_temp += "#";
        }
        for(i = 0; i < s_temp.length(); i++){
            for(j = 0; j <= i && j < s_temp.length() - i; j++){
                if(s_temp.charAt(i - j) != s_temp.charAt(i + j))
                    break;
            }
            if(j > max_len){
                max_len = j - 1;
                pos_start = i;
            }
        }
        String temp = "";
        for(i = pos_start - max_len; i <= pos_start + max_len; i++){
            if(s_temp.charAt(i) != '#')
                temp += s_temp.charAt(i);
        }
        return temp;
    }
}

Manacher’s algorithm

在leetcode给出的源码中,有一个Manacher’s算法,(其实大概也许可能没怎么看懂,先把自己的理解记录一下

首先他的预处理与我之前做的一样,但他同时新建了一个存储以该点为中心的最长对称长度的数组,举个例子
S1 = ababa
T1 = # a # b # a # b # a #
P1 = 0 1 0 3 0 5 0 3 0 1 0

T的构造很简单,在得到了数组P之后找到回文子串也很方便,现在的问题就是如何得到数组P

如下,现在要求P[9]
T = # b # a # b # c # b # a # b # c # b # a # c # c # b # a #
P = 0 1 0 3 0 1 0 7 0 ?
很容易得到如果以T[7]为center的子串radius为7(包含了T[9]),则P[7 + 2] = P[7 - 2]这个结论
现在来看T[9] = T[5] = 1这个结论好像是正确的

但之后就会有错
T = # b # a # b # c # b # a # b # c # b # a # c # c # b # a #
P = 0 1 0 3 0 1 0 7 0 1 0 ?
如果按照上面的方法来推理的话,这里P[7 + 4]属于7 + 7的范围,所以应该等于P[7 - 4] = 3
但按照全局来看,它应该等于9
这就和之前找到的规律相悖了

所以产生了一个新规则
可以看到上面的例子中P[7 + 4]被center P[7]罩着,与之对应的P[7 - 4] = 3,那也就是说,以center = P[3]罩着的数中有center P[7]罩不到的,那就不能做单纯的复制工作了
但我们依然可以确保在center P[7]罩得到的地方,center P[3]回文等于center P[11]的回文,也就是说,对于P[11]不用从11开始计算,从7 + P[7] 开始算起就可以了

那总结一下
我们假设当前要计算的点是i,与之对应的center是center,位于center另一头的是mirror

  • 当i > center + center_radius的时候,从零开始计算
  • 当P[mirror] < P[center] - (i - center)的时候,直接复制P[mirror]的值
    # x # x # x # x # x # x # x # x # x # x # x # x # x # x # x # x #
    假设加粗部分为mirror罩着的位置,黄色部分为center罩着的数字
  • 当i ≤ \le center + P[center] 且P[mirror] > P[center] - (i - center)的时候,从P[center] + center + 1开始计算回文
    # x # x # x # x # x # x # x # x # x # x # x # x # x # x # x # x #
    # x # x # x # x # x # x # x # x # x # x # x # x # x # x # x # x #
    假设同上

java代码如下:

string preProcess(string s) {
	int n = s.length();
	if (n == 0) return "^$";
		string ret = "^";
	for (int i = 0; i < n; i++)
		ret += "#" + s.substr(i, 1);
	ret += "#$";
	return ret;
}
 
string longestPalindrome(string s) {
	string T = preProcess(s);
	int n = T.length();
	int *P = new int[n];
	int C = 0, R = 0;
	for (int i = 1; i < n-1; i++) {
		int i_mirror = 2*C-i;
		P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0;
		while (T[i + 1 + P[i]] == T[i - 1 - P[i]])
			P[i]++;
		if (i + P[i] > R) {
		C = i;
		R = i + P[i];
		}
	}
 
	int maxLen = 0;
	int centerIndex = 0;
	for (int i = 1; i < n-1; i++) {
		if (P[i] > maxLen) {
			maxLen = P[i];
			centerIndex = i;
		}
	}
	delete[] P;
	return s.substr((centerIndex - 1 - maxLen)/2, maxLen);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值