日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2025/3/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 求解最长回文子串----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;} }

總結

以上是生活随笔為你收集整理的求解最长回文子串----Manacher 算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。