Manacher 馬拉車算法

Manacher 馬拉車算法

5. 最長回文子串 - 力扣(LeetCode)

馬拉車算法是目前解決尋找字符串中最長的回文子串時間復雜度最低的算法(線性O(n)).

中心擴散法

初始化一個長度與字符串 s 相等的 臂長數組 arr 和 最長臂長 max 與 最長臂長回文串中心下標 maxIndex , 對字符串 s 進行迭代 , 初始化兩個指針 leftright 分別指向當前位置 i 的兩邊 , 以判斷當前位置字符的左右字符是否相等 和 左右下標是否超過數組邊界 , 若相等且不超過邊界則指針向外擴散并再次判斷 . 退出判斷后檢測更新 maxmaxIndex .

原始的中心擴散法只能處理奇數回文串中心的情況 . 因此需要對原始字符串進行映射擴充 : 在開頭 , 結尾以及字符之間插入任意一個相同的 , 非字符串可能存在的字段的特殊字符 ( 一般為 # ) , 這樣字符串的長度由 n 映射到 2*n+1 , 如果出現偶數回文串中心的情況 , 映射到新字符串則是落在特殊字符上 , 最后還原即可 , 這樣保證了對字符串臂長的計算均建立在奇數中心的情況 .

觀察最壞情況 : 字符串每個字符均相同 , 長度為 n , 則對于每個字符串均需要左右指針擴散計算 , 從 0 次 到 n/2 次 再到 0 次 , 得到計算次數大致為 n^2/4 次 , 時間復雜度為 O(n^2) .

import java.util.StringJoiner;
class Solution {public String longestPalindrome(String s) {int n = s.length();StringJoiner sj = new StringJoiner("#", "#", "#");for(int i = 0; i < n; ++i) {sj.add(s.substring(i, i + 1));}int number = sj.toString().length();char[] charArr = sj.toString().toCharArray();int[] arr = new int[number];int max = 0;int maxIndex = 0;int left, right;for(int i = 0; i < number; ++i) {left = i - 1;right = i + 1;while(left >= 0 && right < number) {if(charArr[left] == charArr[right]){++arr[i];--left;++right;}else break;}if(arr[i] > max) {max = arr[i];maxIndex = i;}}max = (max - 1) / 2;if((maxIndex - 1) % 2 == 1) { // 偶數中心maxIndex = (maxIndex - 1) / 2;return s.substring(maxIndex - max, maxIndex + max + 2);}maxIndex = (maxIndex - 1) / 2;return s.substring(maxIndex - max, maxIndex + max + 1);}
}

Manacher 對中心擴散法的優化

中心擴散法對每個字符進行計算明顯具有冗余 , Manacher 馬拉車算法的目的即是盡可能的減少計算 , 降低時間復雜度 : 注意到回文串的臂長具有 對稱性 : 回文串以中心點為對稱軸 , 其左右兩側的字符是相等的 , 回文串最遠距離內任意非中心字符的臂長可以繼承對應字符的臂長 . 為了實現這一便利 , 我們需要在每次迭代時額外維護兩個量 最右邊界r 和 最右邊界對應的大回文串中心centerIndex .

arr[i] = Math.min(r - i, arr[2 * centerIndex - i]); 是算法的核心語句 , 可以認為當回文子字符的臂長沒有超過大回文的邊界時 , 我們對該該字符是 完全知悉的 , 臂長在大回文內即被截斷 . 若鏡像點的回文半徑較小以至于其完全包含在以 centerIndex 為中心的大回文串中 , 那么當前字符的回文半徑可以直接繼承完全知悉的鏡像點 arr[2 * centerIndex - i] , 不需要再進行計算 ; 若鏡像點的回文半徑較大以至于超出了大回文串的邊界 , 則當前字符的回文半徑至少可以繼承到大回文的最右邊界right - i , 而我們對大回文外的字符分布并不知悉 , 因此后續需要計算嘗試擴展 .

同樣觀察最壞情況 : 字符串的每個字符均相同 , 對于前半字符串的每個位置 n 需要計算 n-(n-1)1 次 , 后半字符串因為鏡像點始終完全知悉 , 直接繼承即可 , 計算次數也為 1 次 , 總計算次數為 n 次 , 時間復雜度為 O(n) .

class Solution {public String longestPalindrome(String s) {int n = s.length();StringBuilder sb = new StringBuilder();sb.append("#");for(int i = 0; i < n; ++i) {sb.append(s.substring(i, i + 1)).append("#");}int number = sb.toString().length();char[] charArr = sb.toString().toCharArray();int[] arr = new int[number];int max = 0;int maxIndex = 0;int r = maxIndex + max;int centerIndex = 0;int left, right;for(int i = 0; i < number; ++i) {left = i - 1;right = i + 1;if(i <= r) {arr[i] = Math.min(r - i, arr[2 * centerIndex - i]); // Manacher核心語句left -= arr[i];right += arr[i];}while(left >= 0 && right < number && charArr[left] == charArr[right]) {++arr[i];--left;++right;}if(arr[i] > max) {max = arr[i];maxIndex = i;}if(r < arr[i] + i) {r = arr[i] + i;centerIndex = i;}}int start = (maxIndex - max) / 2;int end = start + max;return s.substring(start, end);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73099.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73099.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73099.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(學習總結29)Linux 進程概念和進程狀態

Linux 進程概念 馮諾依曼體系結構軟件運行與存儲分級數據流動的理論過程 操作系統操作系統(Operator System) 概念操作系統的功能與作用系統調用和庫函數概念 進程概念描述進程 - PCBtask_struct查看進程通過系統調用獲取進程標示符 PID通過系統調用 fork 函數創建進程簡單使用…

MySQL密碼修改的全部方式一篇詳解

本文將詳細介紹多種修改MySQL密碼的方式。 本文目錄 一、alter user 語句操作步驟 二、set password操作步驟 三、直接修改 mysql.user表操作步驟 一、alter user 語句 當你以 root 用戶或者擁有足夠權限的用戶登錄 MySQL 時&#xff0c;可以使用 ALTER USER 語句來修改密碼。…

Wi-Fi NAN 架構(Wi-Fi Aware Specification v4.0,第2章:2.3~2.6)

1. NAN 數據通信架構 1.1 單播支持 要在兩個NAN設備之間啟動單播數據通信&#xff0c;服務需發起一個NAN數據路徑&#xff08;NDP&#xff0c;NAN Data Path&#xff09;請求。這對NAN設備之間會建立一個NAN設備鏈路&#xff08;NDL&#xff0c;NAN Device Link&#xff09;&…

Lineageos 22.1(Android 15)實現負一屏

一、前言 方案是參考的這位大佬的&#xff0c;大家可以去付費訂閱支持一波。我大概理一下Android15的修改。 大佬的方案代碼 二、Android15適配調整 1.bp調整&#xff0c;加入aidl引入&#xff0c;這樣make之后就可以索引代碼了 filegroup {name: "launcher-src"…

Java 大視界 -- Java 大數據在智能醫療遠程會診與專家協作中的技術支持(146)

&#x1f496;親愛的朋友們&#xff0c;熱烈歡迎來到 青云交的博客&#xff01;能與諸位在此相逢&#xff0c;我倍感榮幸。在這飛速更迭的時代&#xff0c;我們都渴望一方心靈凈土&#xff0c;而 我的博客 正是這樣溫暖的所在。這里為你呈上趣味與實用兼具的知識&#xff0c;也…

Sqlite3數據庫

工具庫的使用&#xff1a;程序編寫時#include <庫名.h>即可調用庫中的函數 編譯時鏈接工具庫&#xff1b; 注意&#xff1a;數據庫中不區分字母大小寫&#xff1b; SQLite 中的事務是數據庫操作中非常重要的一個概念&#xff0c;它用于確保數據庫操作的完整性和一致性。…

虛擬路由與單頁應用(SPA):詳解

在單頁應用&#xff08;SPA&#xff0c;Single Page Application&#xff09;中&#xff0c;虛擬路由&#xff08;也稱為前端路由&#xff09;是一種關鍵的技術&#xff0c;用于管理頁面導航和狀態變化&#xff0c;而無需重新加載整個頁面。為了幫助你更好地理解這一概念&#…

練習:運動計劃

需求&#xff1a;鍵盤錄入星期數&#xff0c;顯示今天的減肥活動。 周一&#xff1a;跑步&#xff1b; 周二&#xff1a;游泳&#xff1b; 周三&#xff1a;慢走&#xff1b; 周四&#xff1a;騎動感單車&#xff1b; 周五&#xff1a;拳擊&#xff1b; 周六&#xff1a;…

通過webrtc+canvas+css實現簡單的電腦濾鏡拍照效果

這里我們用的是webrtc中的MediaDevices.getUserMedia()的瀏覽器api進行的效果實現&#xff0c;MediaDevices.getUserMedia() 會提示用戶給予使用媒體輸入的許可&#xff0c;媒體輸入會產生一個MediaStream&#xff0c;里面包含了請求的媒體類型的軌道。此流可以包含一個視頻軌道…

《TCP/IP網絡編程》學習筆記 | Chapter 20:Windows 中的線程同步

《TCP/IP網絡編程》學習筆記 | Chapter 20&#xff1a;Windows 中的線程同步 《TCP/IP網絡編程》學習筆記 | Chapter 20&#xff1a;Windows 中的線程同步用戶模式和內核模式用戶模式同步內核模式同步 基于 CRITICAL_SECTION 的同步內核模式的同步方法基于互斥量對象的同步基于…

VBA-Excel

VBA 一、數據類型與變量 常用數據類型&#xff1a; Byte&#xff1a;字節型&#xff0c;0~255。Integer&#xff1a;整數型&#xff0c;用于存儲整數值&#xff0c;范圍 -32768 到 32767。Long&#xff1a;長整型&#xff0c;可存儲更大范圍的整數&#xff0c;范圍 -214748364…

kotlin 內聯函數 inline

高階函數實現的原理&#xff1a;函數類型其實是生成了一個對象 。 inline翻譯成中文的意思就是內聯&#xff0c;在kotlin里面inline被用來修飾函數&#xff0c;表明當前函數在編譯時是以內嵌的形式進行編譯的&#xff0c;從而減少了一層函數調用棧&#xff1a; inline fun fun…

PairRE: Knowledge Graph Embeddings via Paired Relation Vectors(論文筆記)

CCF等級&#xff1a;A 發布時間&#xff1a;2020年11月 25年3月24日交 目錄 一、簡介 二、原理 1.整體 2.關系模式 3.優化模型 三、實驗性能 四、結論和未來工作 一、簡介 將RotatE進行生級&#xff0c;RotatE只對頭實體h進行計算&#xff0c;PairRE對頭尾實體都進行…

從報錯到成功:Mermaid 流程圖語法避坑指南?

&#x1f680; 從報錯到成功&#xff1a;Mermaid 流程圖語法避坑指南 &#x1f680; &#x1f6a8; 問題背景 在開發文檔或技術博客中&#xff0c;我們經常使用 Mermaid 流程圖 來可視化代碼邏輯。但最近我在嘗試繪制一個 Java Stream 轉換流程圖時&#xff0c;遭遇了以下報錯…

深入解析 Redis 實現分布式鎖的最佳實踐

前言 在分布式系統中&#xff0c;多個進程或線程可能會同時訪問同一個共享資源&#xff0c;這就可能導致數據不一致的問題。為了保證數據的一致性&#xff0c;我們通常需要使用分布式鎖。Redis 作為高性能的內存數據庫&#xff0c;提供了一種簡單高效的方式來實現分布式鎖。本…

2025年03月10日人慧前端面試(外包滴滴)

目錄 普通函數和箭頭函數的區別loader 和 plugin 的區別webpack 怎么實現分包&#xff0c;為什么要分包webpack 的構建流程變量提升react 開發中遇到過什么問題什么是閉包vue 開發中遇到過什么問題vue中的 dep 和 watcher 的依賴收集是什么階段什么是原型鏈react setState 是同…

Android10 系統截屏功能異常的處理

客戶反饋的問題&#xff0c;設備上使用狀態欄中“長截屏”功能&#xff0c;截屏失敗且出現系統卡死問題。 在此記錄該問題的處理 一現象&#xff1a; 設備A10上使用系統“長截屏”功能&#xff0c;出現截屏失敗&#xff0c;系統死機。 二復現問題并分析 使用設備操作該功能&…

openvela新時代的國產開源RTOS系統

openvela 簡介 openvela 操作系統專為 AIoT 領域量身定制&#xff0c;以輕量化、標準兼容、安全性和高度可擴展性為核心特點。openvela 以其卓越的技術優勢&#xff0c;已成為眾多物聯網設備和 AI 硬件的技術首選&#xff0c;涵蓋了智能手表、運動手環、智能音箱、耳機、智能家…

ENSP學習day9

ACL訪問控制列表實驗 ACL&#xff08;Access Control List&#xff0c;訪問控制列表&#xff09;是一種用于控制用戶或系統對資源&#xff08;如文件、文件夾、網絡等&#xff09;訪問權限的機制。通過ACL&#xff0c;系統管理員可以定義哪些用戶或系統可以訪問特定資源&#x…

JVM的組成--運行時數據區

JVM的組成 1、類加載器&#xff08;ClassLoader&#xff09; 類加載器負責將字節碼文件從文件系統中加載到JVM中&#xff0c;分為&#xff1a;加載、鏈接&#xff08;驗證、準備、解析&#xff09;、和初始化三個階段 2、運行時數據區 運行時數據區包括&#xff1a;程序計數…