字符串匹配算法

Manacher算法

由于回文分为偶回文(比如 bccb)和奇回文(比如 bcacb),而在处理奇偶问题上会比较繁琐,所以这里我们使用一个技巧,具体做法是:在字符串首尾,及各字符间各插入一个字符(前提这个字符未出现在串里)。

举个例子:s="abbahopxpo",转换为s_new="$#a#b#b#a#h#o#p#x#p#o#"(这里的字符 $ 只是为了防止越界,下面代码会有说明),如此,s 里起初有一个偶回文abba和一个奇回文opxpo,被转换为#a#b#b#a##o#p#x#p#o#,长度都转换成了奇数

定义一个辅助数组int p[],其中p[i]表示以 i 为中心的最长回文的半径,例如:

i012345678910111213141516171819
s_new[i]$#a#b#b#a#h#o#p#x#p#
p[i]1212521212121214121

可以看出,p[i] - 1正好是原字符串中最长回文串的长度。

接下来的重点就是求解 p 数组,如下图:

img

设置两个变量,mx 和 id 。mx 代表以 id 为中心的最长回文的右边界,也就是mx = id + p[id]

假设我们现在求p[i],也就是以 i 为中心的最长回文半径,如果i < mx,如上图,那么:

if (i < mx)  
    p[i] = min(p[2 * id - i], mx - i);

2 * id - i为 i 关于 id 的对称点,即上图的 j 点,而**p[j]表示以 j 为中心的最长回文半径**,因此我们可以利用p[j]来加快查找。

根据回文的性质,p[i]的值基于以下三种情况得出:

(1):j 的回文串有一部分在 id 的之外,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zbb5uFQX-1584521572662)(https://resource.ethsonliu.com/image/20180403_03.png)]

上图中,黑线为 id 的回文,i 与 j 关于 id 对称,红线为 j 的回文。那么根据代码此时p[i] = mx - i,即紫线。那么p[i]还可以更大么?答案是不可能!见下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eFlxIbky-1584521572663)(https://resource.ethsonliu.com/image/20180403_04.png)]

假设右侧新增的紫色部分是p[i]可以增加的部分,那么根据回文的性质,a 等于 d ,也就是说 id 的回文不仅仅是黑线,而是黑线+两条紫线,矛盾,所以假设不成立,故p[i] = mx - i,不可以再增加一分。

(2):j 回文串全部在 id 的内部,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MJAw6ukh-1584521572663)(https://resource.ethsonliu.com/image/20180403_05.png)]

根据代码,此时p[i] = p[j],那么p[i]还可以更大么?答案亦是不可能!见下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LiHB310Z-1584521572664)(https://resource.ethsonliu.com/image/20180403_06.png)]

假设右侧新增的红色部分是p[i]可以增加的部分,那么根据回文的性质,a 等于 b ,也就是说 j 的回文应该再加上 a 和 b ,矛盾,所以假设不成立,故p[i] = p[j],也不可以再增加一分。

(3):j 回文串左端正好与 id 的回文串左端重合,见下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gVQNFLfW-1584521572664)(https://resource.ethsonliu.com/image/20180403_07.png)]

根据代码,此时p[i] = p[j]p[i] = mx - i,并且p[i]还可以继续增加,所以需要

while (s_new[i - p[i]] == s_new[i + p[i]]) 
    p[i]++;
package main
import(
	"fmt"
)

func CenterSpread(s string, center int) int{
	l := len(s)
	i := center - 1
	j := center +1
	step := 0
	for i >= 0 && j < l && s[i] == s[j] {
		i--
		j++
		step++
	}
	return step
}

func longestPalindrome(s string) string{
	l := len(s)
	if l < 2 {
		return s
	}

	str := "$"
	for i := 0; i < l; i++ {
		str += string(s[i])
		str += "#"
	}
	size := 2*l+1
	max := 1

	start := 0
	for i := 0; i < size; i++ {
		curLen := CenterSpread(str, i)
		if curLen > max {
			max = curLen
			start = (i - max) / 2
		}
	}
	return s[start:start+max]
}

func main () {
	s := "cbbd"
	fmt.Println(longestPalindrome(s))
}

Manacher

func longestPalindrome(s string) string {
    if s == "" {
        return s
    }
    sByte := []byte(s)
    sNew := []byte{}
    sNew = append(sNew,'$')
    l := len(s)
    for i := 0; i < l; i++ {
        sNew = append(sNew, '#')
        sNew = append(sNew, sByte[i])
    }
    sNew = append(sNew, '#')
    sNew = append(sNew, '\\')



    s1 := string(manacher(sNew))
    return s1
}

func manacher(sNew []byte) []byte {
    p := make(map[int]int)
    maxMid := 0
    p[maxMid] = 1
    maxRight := maxMid + p[maxMid] - 1

    result := 0


    length := len(sNew) - 1

    for i := 1; i < length; i++ {

        if i <= maxRight {
            if p[2*maxMid - i] <= maxRight - i + 1 {
                p[i] = p[2*maxMid-i]
            } else {
                p[i] = maxRight - i + 1
            }
        } else {
            p[i] = 1
        }
        for sNew[i-p[i]] == sNew[i+p[i]] {
            p[i]++
        }
        if i+p[i]-1 > maxRight {
            if p[i] > p[result] {
                result = i
            }
            maxMid = i
            maxRight = i + p[i] -1
        }
    }
    sFinal := []byte{}
    for i := result-p[result]+2; i <= result+p[result]-2; i += 2{
        sFinal = append(sFinal, sNew[i])
    }
    return sFinal
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值