找到最长回文字符串 - Manacher's Algorithm
2016-10-03 09:22
465 查看
记得刚开始学习计算机的时候,除了输出星星就是找到最长回文字符串这样的问题, 开始以为最长回文串问题很简单,但是经过多年的学习再回头看的时候发现,它并不简单,今天就给它解个密。
开始我们先来看一个时间复杂度差的算法。
1. 时间复杂度为 n^3. 空间复杂度为 1. 这个算法基本上是最简单的了,最好理解的。
2. Manacher's Algorithm - 时间复杂度为 N ( 应该大于N 小于 N ^ 2)
这个算法需要一个预处理和主要的三个变量。
预处理: 将输入字符串的各个字符使用特殊字符进行 分割,比如 #。 e.g. input: abba 处理: #a#b#b#a#
三个主要变量:
1. 一个和预处理之后大小一样的 int 数组 rad[] - 用来存储以当前字符为中心的最长子回文字符串的半径。
2. 一个整形变量来存储- 我们遍历过的所有子回文字符串能触及到的最右边的位置的maxRight。
3. 另一个整形变量来存储 - 2.中maxRight所对应的 子回文字符串的中心点的位置pos。
每次遍历从以当前字符为中心向两头扩展,扩展的半径是多少?
这就是个问题。。。
解决办法, 通过对比 i 和 maxRight, 当i < maxRight 的时候, 判断 maxRight - i 的大小 和 一个点 j ( 这个点是 i 以 pos为对称的 对称点 )的最长回文半径的大小(存储在rad 中).
使用较小值作为半径, 从当前点开始进行两头扩张。每次扩张成功之后半径+1。
有问题欢迎指出。
开始我们先来看一个时间复杂度差的算法。
1. 时间复杂度为 n^3. 空间复杂度为 1. 这个算法基本上是最简单的了,最好理解的。
/** * 使用iteration * 循环三次 * 第一次(最外边循环 : 从最长的长度开始,循环长度,每次减1 * 第二次 (中间循环): 对每个长度,循环最长字符串的起始点,起点从0每次加1 * 第三次 (最内循环): 对每个长度每个起点,对左右进行比较,每次左+1,右-1 * * * * * */ public static String longestP (String S) { if (S.length() < 2 || S == null) { return S; } int length = S.length(); int left = 0; int right = 0; while (length >= 0) { for (int i = 0; i + length - 1 < S.length(); i++) { left = i; right = i + length - 1; while (left < right) { if (S.charAt(left) == S.charAt(right)) { left ++; right --; continue; } else { break; } } if (left >= right) { return S.substring(i, i+ length); } } length --; } return ""; }
2. Manacher's Algorithm - 时间复杂度为 N ( 应该大于N 小于 N ^ 2)
这个算法需要一个预处理和主要的三个变量。
预处理: 将输入字符串的各个字符使用特殊字符进行 分割,比如 #。 e.g. input: abba 处理: #a#b#b#a#
三个主要变量:
1. 一个和预处理之后大小一样的 int 数组 rad[] - 用来存储以当前字符为中心的最长子回文字符串的半径。
2. 一个整形变量来存储- 我们遍历过的所有子回文字符串能触及到的最右边的位置的maxRight。
3. 另一个整形变量来存储 - 2.中maxRight所对应的 子回文字符串的中心点的位置pos。
每次遍历从以当前字符为中心向两头扩展,扩展的半径是多少?
这就是个问题。。。
解决办法, 通过对比 i 和 maxRight, 当i < maxRight 的时候, 判断 maxRight - i 的大小 和 一个点 j ( 这个点是 i 以 pos为对称的 对称点 )的最长回文半径的大小(存储在rad 中).
使用较小值作为半径, 从当前点开始进行两头扩张。每次扩张成功之后半径+1。
public static String Manacher (String S) { if (S.length() < 2 || S == null) { return S; } //construct new string //basically, insert one # to the String S, //make sure each character is surrounded by # StringBuilder newS = new StringBuilder(); newS.append("#"); int start = 0; while (start < S.length()) { newS.append(S.charAt(start)); newS.append("#"); start ++; } int [] rad = new int[newS.length()]; //to store the radius of a string with pivot of current node int maxRight = -1; //most right we can touch. int pos = -1; //the position for which node that can touch the most right. for (int i = 0; i < newS.length(); i++) { int r = 1; //radius if (i <= maxRight) { //since i is less than the max right, //so we can compare the radius of the node which is symmetric with pos and centered on current node r = Math.min(rad[2*pos - i], maxRight - i); } //extend the string, compare with the i - r(left) and i + r (right) //if they equal, so that radius ++ while (i - r >= 0 && i + r < newS.length() && newS.charAt(i-r) == newS.charAt(i+r)) { r++; } //if i + r -1 is greater than the most right that the most right we can touch. //we have to update the max right and the position of max right if (i + r - 1 > maxRight) { maxRight = i + r - 1; pos = i; } rad[i] = r; } int MaxR = 0; int pivot = 0; for (int i = 0; i < rad.length; i++) { if (rad[i] > MaxR) { MaxR = rad[i]; pivot = i; } } return newS.substring(pivot - MaxR + 1, pivot + MaxR).replace("#", ""); }
有问题欢迎指出。
相关文章推荐
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's Algorithm 求解字符串的最长回文串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher算法求字符串的最长回文子串
- 给一个字符串,找到其最长的回文字串
- 最长回文字符串算法-Manacher’s Algorithm-马拉车算法
- HDU 3068 最长回文 [Manacher]【字符串】
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- 字符串 manacher 最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher算法:求解最长回文字符串,时间复杂度为O(N)
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher’s algorithm(最长回文子串)
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- 求解字符串的最长回文子串的Manacher’s Algorithm
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串