求解最长回文子串----Manacher 算法

最长回文子串问题:给定一个字符串,求它的最长回文子串长度。

如果一个字符串正着读和反着读是一样的,那么我们称之为回文串。例如:abba、aaaa、abvcba、123321等

暴力法:遍历字符串的所有子串,对每个字串进行判断。求字符串的所有子串时间复杂度为O(n^2),判断回文后,总的时间复杂度为O(n^3)。我们规定在判断回文的时候从最长的子串开始,一旦找到就返回。判断回文的时候,采用从外到内左右成对推进方式进行。

import java.util.Scanner;public class Main {static String str = new String();public static void main(String[] args) {Scanner in = new Scanner(System.in);str = in.next();System.out.println(sub());}private static int sub() {int low, high;for (int len = str.length() - 1; len > 0; len--) {for (low = 0, high = low + len; high < str.length(); low++, high++) {if (check(low, high)) {return high - low + 1;}}}return 1;}private static boolean check(int low, int high) {while (low <= high) {if (str.charAt(low) == str.charAt(high)) {low++;high--;} else {return false;}}return true;}
}

从内到外逐个推进方式:由于回文串的特性,我们可以以每个位置为中心进行检查,这样可以不用暴力所有的子串,减少了重复的判断。时间复杂度为O(n^2)。这里要注意检查是要关注奇偶的不同情况,如abba和aba。

import java.util.Scanner;public class Main2 {static String str = new String();static int max = 0;public static void main(String[] args) {Scanner in = new Scanner(System.in);str = in.next();sub();System.out.println(max);}private static void sub() {if (str.length() == 1) {max = 1;}for (int i = 0; i < str.length() - 1; i++) {check(i, i);check(i, i+1);}}private static void check(int low, int high) {while (low >= 0 && high < str.length()) {if (str.charAt(low) == str.charAt(high)) {if (high - low + 1 > max) {max =  high - low + 1;}low--;high++;} else {return;}}}
}

Manacher算法:俗称马拉车算法。这是目前求解最长回文串的最优算法。第二种思路在会将从str.charAt(0)一直检查到str.charAt(lstr.length-1),这样的话还是有许多不必要的操作,而这种算法的核心就在于优化了这一块的判断,跳过某些不必要的值。

由于回文串会出现奇数和偶数不同的情况,如abba和abcba,算法采用插入“#”的方法,使得所有的串都变成奇数串(“$”是占0的位置,从1开始方便操作),这个新的串我们命名为s_new[]。之后定义p[],用p[i]表示以s_new[i]为中心的最长回文串的半径(包含自身),如abcba的s_new["c"] = 3 (半径为2,再加自身)。我们以字符串abbabcbac为例,最长回文子串为abcba,长度为5。

i012345678910111213141516171819
s_new[i]$#a#b#b#a#b#c#b#a#c#
p[i] 1212521412161212121

那么如何计算p[i]就成了这个算法的难点,我们自然不能按着思路二:先令p[i]=1,再以s_new[i]为中心判断两侧是否相等,p[i]++,这是非常低效的。实际上,我们可以不让p[i]初始化为1,我们设定两个变量mx和id,id为s_new[i]的下标(也就是i),mx表示以s_new[id]为中心的最长回文串的右侧边界,以abcba为例,s_new["c"] = 3,id=2("c"的下标),对应的mx=id+s_new["c"] = 5,刚好就是最右侧"a"的下标。

结合下图,对于i<mx的情况 , 存在p[i] = min(p [2*id-i], mx-i)。


解释一下上面式子,2*id-i = j,所以p[2*id - i] = p[j],即以s_new[j]为中心的最长回文串的半径(包含自身)。因为以id为中心的回文子串的长度为mx与其对称点之间的距离,而要求p[i],则可以利用p[j]来加快查找。

而之所以上面的式子成立是需要深入探讨的,有兴趣的朋友可以参考Manacher算法

import java.util.Scanner;public class Main {static String str = new String();static char[] s_new;static int[] p;public static void main(String[] args) {Scanner in = new Scanner(System.in);str = in.next();s_new = new char[str.length() * 2 + 2];p = new int[str.length() * 2 + 2];System.out.println(Manacher());}private static int Manacher() {// TODO Auto-generated method stubint len = init();int maxlen = -1;int id = 0;int mx = 0;for (int i = 1; i < len; i++) {if (i < mx) {p[i] = Math.min(p[2 * id - i], mx - i);} else {p[i] = 1;}while (i + p[i] < s_new.length && i - p[i] >= 0 &&s_new[i - p[i]] == s_new[i + p[i]]) {p[i]++;}if (mx < i + p[i]) {id = i;mx = i + p[i];}maxlen = Math.max(maxlen, p[i] - 1);}return maxlen;}private static int init() {// TODO Auto-generated method stubs_new[0] = '$';s_new[1] = '#';int j = 2;for (int i = 0; i < str.length(); i++) {s_new[j++] = str.charAt(i);s_new[j++] = '#';}return j;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569712.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Peter's smokes -poj 2509

题意&#xff1a;彼得有n支雪茄&#xff0c;每k个烟头可以换一支新雪茄&#xff0c;问彼得最多可以吸多少支雪茄 &#xff1f; 当时自己做时&#xff0c;错在了直接在while循环开始前&#xff0c;便将雪茄的初始数量给加上了&#xff0c;然而应该是先处理后再加上最终剩余的雪茄…

模式匹配算法----KMP算法以及next数组的解法

KMP算法&#xff1a;求字符串匹配&#xff08;也叫模式匹配&#xff09;的算法&#xff0c;即给定一个字符串&#xff0c;求其某一子串在其中出现的位置。 普通模式匹配 例如&#xff1a;给定字符串为abcabaaabaabcac&#xff0c;求其子串abaabcac在其中出现的位置。 结果为…

Spring Boot使用layui的字体图标时无法正常显示 解决办法

在html文件使用字体图标并且预览时正常&#xff0c;但是启动工程后显示不正常&#xff0c;浏览器调试界面显示字体文件无法decode&#xff1a; Failed to decode downloaded font: xxxxx 如图所示&#xff1a; 显示结果&#xff1a; 原因&#xff1a;经过maven的filter&#xf…

蓝桥杯第七届国赛JAVA真题----机器人塔

机器人塔X星球的机器人表演拉拉队有两种服装&#xff0c;A和B。 他们这次表演的是搭机器人塔。 类似&#xff1a;队内的组塔规则是&#xff1a; A 只能站在 AA 或 BB 的肩上。B 只能站在 AB 或 BA 的肩上。你的任务是帮助拉拉队计算一下&#xff0c;在给定A与B的人数时&…

致自己人生的一句话

千锤万凿出深山 烈火焚烧若等闲 转载于:https://www.cnblogs.com/wuhefeng/p/10467737.html

单链表常见操作

最近在重新学习数据结构和算法的知识&#xff0c;数据结构和算法问题本身比较枯燥和乏味&#xff0c;而且比较难不容易掌握&#xff0c;但是属于程序员内功的一部分&#xff0c;学习起来容易上瘾。 1. 单链表定义 package algorithm.datastructors;/*** 单向链表* author i3247…

蓝桥杯第五届省赛JAVA真题----最长公共子序列

一个串的子串是指该串的一个连续的局部。如果不要求连续&#xff0c;则可称为它的子序列。 比如对串&#xff1a; "abcdefg" 而言&#xff0c;"ab","abd","bdef" 等都是它的子序列。 特别地&#xff0c;一个串本身&#xff0c;以及空串…

Python divmod() 函数

Python divmod() 函数 Python 内置函数 python divmod() 函数把除数和余数运算结果结合起来&#xff0c;返回一个包含商和余数的元组(a // b, a % b)。 在 python 2.3 版本之前不允许处理复数。 函数语法 divmod(a, b)参数说明&#xff1a; a: 数字b: 数字实例 >>>div…

蓝桥杯第五届省赛JAVA真题----单位分数

形如&#xff1a;1/a 的分数称为单位分数。 可以把1分解为若干个互不相同的单位分数之和。 例如&#xff1a; 1 1/2 1/3 1/9 1/18 1 1/2 1/3 1/10 1/15 1 1/3 1/5 1/7 1/9 1/11 1/15 1/35 1/45 1/231 等等&#xff0c;类似这样的分解无穷无尽。我们增加一个约…

.NET面试题总结

1、c#垃圾回收机制 从以下方面入手展开&#xff1a; 1、压缩合并算法 2、代的机制 3、GC调用终结器 2、委托和事件 先说它的定义&#xff1a;委托的本质是类&#xff0c;类型安全的指针&#xff0c;然后从用途上考虑&#xff0c;事件是包装的委托&#xff0c;但事件不是委托…

蓝桥杯第六届省赛JAVA真题----垒骰子

垒骰子 赌圣atm晚年迷恋上了垒骰子&#xff0c;就是把骰子一个垒在另一个上边&#xff0c;不能歪歪扭扭&#xff0c;要垒成方柱体。 经过长期观察&#xff0c;atm 发现了稳定骰子的奥秘&#xff1a;有些数字的面贴着会互相排斥&#xff01; 我们先来规范一下骰子&#xff1a;1 …

JAVA应试技巧----大数开方

大数开方--牛顿迭代法&#xff1a; 如果一个数的位数为偶数个&#xff0c;那么这个数开方之后就有n/2位&#xff1b; 如果一个数的位数为奇数个&#xff0c;那么这个数开方之后就有n/21位&#xff1b; 我们以num1000为例&#xff0c;位数为4&#xff0c;偶数&#xff0c;那么开…

蓝桥杯历届试题----矩阵翻硬币

矩阵翻硬币 问题描述 小明先把硬币摆成了一个 n 行 m 列的矩阵。随后&#xff0c;小明对每一个硬币分别进行一次 Q 操作。对第x行第y列的硬币进行 Q 操作的定义&#xff1a;将所有第 i*x 行&#xff0c;第 j*y 列的硬币进行翻转。其中i和j为任意使操作可行的正整数&#xff0…

并发队列、线程池、锁

1、CountDownLatch(计数器) CountDownLatch 类位于java.util.concurrent包下&#xff0c;利用它可以实现类似计数器的功能。比如有一个任务A&#xff0c;它要等待其他任务执行完毕之后才能执行&#xff0c;此时就可以利用CountDownLatch来实现这种功能了。CountDownLatch是…

POJ 1088----滑雪(DP)

原题连接&#xff1a;http://poj.org/problem?id1088 Description Michael喜欢滑雪百这并不奇怪&#xff0c; 因为滑雪的确很刺激。可是为了获得速度&#xff0c;滑的区域必须向下倾斜&#xff0c;而且当你滑到坡底&#xff0c;你不得不再次走上坡或者等待升降机来载你。Mic…

Vijos 1603 ----迷宫(矩阵乘法,矩阵快速幂)

描述 在某个神秘的星球上有一个游乐园 游乐园里有一个奇怪的迷宫&#xff0c;迷宫内有n个点&#xff0c;每个点之间都可能会有一条有向边&#xff08;可能会有自环&#xff09; 现在游乐园主有个问题想请你帮忙&#xff1a; 问&#xff1a;从s点走到f点&#xff0c;恰好走过…

蓝桥杯第六届省赛JAVA真题----循环节长度

循环节长度 两个整数做除法&#xff0c;有时会产生循环小数&#xff0c;其循环部分称为&#xff1a;循环节。 比如&#xff0c;11/136>0.846153846153….. 其循环节为[846153] 共有6位。 下面的方法&#xff0c;可以求出循环节的长度。 请仔细阅读代码&#xff0c;并填写…

蓝桥杯第六届省赛JAVA真题----打印菱形

打印菱形 给出菱形的边长&#xff0c;在控制台上打印出一个菱形来。 为了便于比对空格&#xff0c;我们把空格用句点代替。 当边长为8时&#xff0c;菱形为&#xff1a; .......* ......*.* .....*...* ....*.....* ...*.......* ..*.........* .*...........* *..........…

蓝桥杯第六届省赛JAVA真题----生命之树

生命之树 在X森林里&#xff0c;上帝创建了生命之树。 他给每棵树的每个节点&#xff08;叶子也称为一个节点&#xff09;上&#xff0c;都标了一个整数&#xff0c;代表这个点的和谐值。 上帝要在这棵树内选出一个非空节点集S&#xff0c;使得对于S中的任意两个点a,b&#…

蓝桥杯第七届省赛JAVA真题----剪邮票

剪邮票 如【图1.jpg】, 有12张连在一起的12生肖的邮票。 现在你要从中剪下5张来&#xff0c;要求必须是连着的。 &#xff08;仅仅连接一个角不算相连&#xff09; 比如&#xff0c;【图2.jpg】&#xff0c;【图3.jpg】中&#xff0c;粉红色所示部分就是合格的剪取。 请你…