LeetCode5.最長回文子串

?昨天和之前打比賽的隊友聊天,他說他面百度面到這道算法題,然后他用暴力法解的,面試官讓他優化他沒優化出來,這道題我之前沒寫過,我就想看看我能不能用效率高一點的方法把它做出來,我一開始就在想用遞歸或者翻轉字符串等等技巧,想了半個多小時都想不到,然后算了,我也用暴力法吧,然后就寫了如下代碼:

class Solution {public String longestPalindrome(String s) {int n = s.length();String ans = "";for(int i = 0;i<n;i++){int l = i, r=i;while(l<= r && l >=0 && r < n && s.charAt(l) == s.charAt(r)){String tem =s.substring(l,r+1);if(r-l+1 > ans.length())ans=tem;l--;r++;}l = i;r=l+1;while(l >=0 && r < n && s.charAt(l) == s.charAt(r)){String tem =s.substring(l,r+1);if(r-l+1 > ans.length())ans=tem;l--;r++;}}return ans;}}

這個暴力法就非常簡單了,就是遍歷字符的每個字符,然后以這個字符為中心用左右指針往兩邊移動,然后是寫了兩個while,一個是左右指針指向同一個字符然后向左右移動,還有一個是左右指針指向相鄰的字符向兩邊移動。

還是看看官方題解的做法吧。

題解的方法一是用的動態規劃:

class Solution {public String longestPalindrome(String s) {int len = s.length();if(len < 2)return s;boolean[][] dp = new boolean[len][len];for(int i=0;i<len;i++){dp[i][i] = true;}int begin =0;int maxLen =1;char[] str = s.toCharArray();for(int L =2;L<=len;L++){for(int i=0;i<len;i++){int j = i+L-1;if(j>=len){break;}else{if(str[i] != str[j]){dp[i][j] = false;}else{if(j-i<3){dp[i][j] = true;}else{dp[i][j] = dp[i+1][j-1];}}}if(dp[i][j] && j-i+1 > maxLen){maxLen = j-i+1;begin = i;}}}return s.substring(begin, begin+maxLen);}}

dp[i][j]表示s的第i個字符到第j個字符這一個子串是不是一個回文字符串。

首先,初始狀態:dp[i][i] = true;

然后,狀態轉移方程:dp[i][j] = ?

第一種情況,s.charAt(i) != s.charAt(j), 那么dp[i][j] = false;

第二種情況,s.charAt(i) == s.charAt(j),如果子串長度小于3,那么dp[i][j]=true;否則dp[i][j] = dp[i-1][j+1]

只要找出dp[i][j]中為true且長度最大的那個就行,這一步在填充dp的數組的同時進行,不用另外遍歷,只要一個max動態更新就行。然后值得注意的是這里是把字符串轉成了字符數組,因為我們需要頻繁的找字符串中的字符,用數組效率更高,用charAt方法需要遍歷字符串,而數組可以直接通過尋址公式得出。

題解的第二種方法用的是中心擴展,和我的方法差不多,只是它把while循環封裝成了函數而已,以下是題解方法二代碼:

class Solution {public String longestPalindrome(String s) {if (s == null || s.length() < 1) {return "";}int start = 0, end = 0;for (int i = 0; i < s.length(); i++) {int len1 = expandAroundCenter(s, i, i);int len2 = expandAroundCenter(s, i, i + 1);int len = Math.max(len1, len2);if (len > end - start) {start = i - (len - 1) / 2;end = i + len / 2;}}return s.substring(start, end + 1);}public int expandAroundCenter(String s, int left, int right) {while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {--left;++right;}return right - left - 1;}
}

題解的方法三就比較高級了,時間復雜度只有O(n),叫Manacher算法:

定義一個概念”臂長“,如果一個回文字符串的長度是2*lenght+1,那么這個回文字符串的臂長就是length。

如果位置j的臂長為length那么如何找到位置i的臂長呢?

對于奇數長度的回文字符串而言:

如果i關于j的對稱點2*j-i的臂長是n,那么位置i的臂長是min(n,2*j-i)。這個其實很好理解,因為j左右length拿一段是對稱的,所以如果2*j-i有n的臂長按道理i也是這么大的臂長,但是只有length這一部分是對稱的,而2*j-i的對稱部分還可以向兩邊擴展,所以i的臂長只能取n和2*j-i的最小值。

偶數長度的回文字符串呢?

我們通過在字符串的兩頭和沒兩個字符之間加上#,這樣無論奇數還是偶數長度的回文字符串都變成了奇數長度的回文字符串,比如aaba處理成#a#a#b#a#,偶數長度的回文字符串aa變成了#a#a#。aba還是變成奇數#a#b#a#。需要注意的是這里添加的#需要是字符串里面沒有出現過的。最后記得把回文字符還原,把#去掉。以下是Manacher方法的代碼:

class Solution {public String longestPalindrome(String s) {int start = 0, end = -1;StringBuffer t = new StringBuffer("#");for (int i = 0; i < s.length(); ++i) {t.append(s.charAt(i));t.append('#');}t.append('#');s = t.toString();List<Integer> arm_len = new ArrayList<Integer>();int right = -1, j = -1;for (int i = 0; i < s.length(); ++i) {int cur_arm_len;if (right >= i) {int i_sym = j * 2 - i;int min_arm_len = Math.min(arm_len.get(i_sym), right - i);cur_arm_len = expand(s, i - min_arm_len, i + min_arm_len);} else {cur_arm_len = expand(s, i, i);}arm_len.add(cur_arm_len);if (i + cur_arm_len > right) {j = i;right = i + cur_arm_len;}if (cur_arm_len * 2 + 1 > end - start) {start = i - cur_arm_len;end = i + cur_arm_len;}}StringBuffer ans = new StringBuffer();for (int i = start; i <= end; ++i) {if (s.charAt(i) != '#') {ans.append(s.charAt(i));}}return ans.toString();}public int expand(String s, int left, int right) {while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {--left;++right;}return (right - left - 2) / 2;}
}

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

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

相關文章

springboot(ssm滁州市特產銷售系統 特產商城系統Java系統

springboot(ssm滁州市特產銷售系統 特產商城系統Java系統 開發語言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服務器&#xff1a;tomcat 數據庫&#xff1a;mysql 5.7&#xff08;或8.0&#xff09; …

解決錯誤:sudo debtap -u curl: (22) The requested URL returned error: 404

具體錯誤 $ sudo debtap -u > Synchronizing pkgfile database... :: Updating 2 repos...core is up to dateextra is up to date > Synchronizing debtap database...% Total % Received % Xferd Average Speed Time Time Time CurrentDload Upload …

設計CPU功能的數字電路

實驗目的(1)熟悉Multisim 電路仿真軟件的操作界面和功能; (2)掌握邏輯電路綜合設計,并采用仿真軟件進行仿真。 實驗內容1.試設計一個簡易CPU功能的數字電路,實驗至少要求采用4個74HC/HCT194作為4個存儲單元(可以預先對存儲單元存儲數據),74HC283作為計算單元。請實現…

用相似對角矩陣加速矩陣的冪,以斐波那契數列為例

《用相似對角矩陣加速矩陣的冪&#xff0c;以斐波那契數列為例》 在計算機科學和線性代數領域&#xff0c;矩陣的冪是一個常見而重要的問題。特別是對于大型矩陣&#xff0c;直接計算冪可能會變得十分耗時。然而&#xff0c;通過相似對角矩陣的方法&#xff0c;我們能夠以更為…

多維時序 | MATLAB實現RIME-CNN-LSTM-Multihead-Attention多頭注意力機制多變量時間序列預測

多維時序 | MATLAB實現RIME-CNN-LSTM-Multihead-Attention多頭注意力機制多變量時間序列預測 目錄 多維時序 | MATLAB實現RIME-CNN-LSTM-Multihead-Attention多頭注意力機制多變量時間序列預測預測效果基本介紹模型描述程序設計參考資料 預測效果 基本介紹 MATLAB實現RIME-CNN-…

python字符串格式化--數字精度控制和快速寫法與表達式格式化

數字精度控制 我們可以使用m.n來控制數字的寬度和精度&#xff1a; m是寬度&#xff0c;設置必須為數字&#xff0c;且如果設置的數字小于本身&#xff0c;則不生效n控制小數點精度&#xff0c;必須為數字&#xff0c;會進行四舍五入 示例&#xff1a; 5d&#xff1a;是將寬…

idea本地調試hadoop 遇到的幾個問題

1.DEA對MapReduce的toString調用報錯&#xff1a;Method threw ‘java.lang.IllegalStateException‘ exception. Cannot evaluate org.apache.hadoop.mapreduc 解決方法&#xff1a;關閉 IDEA 中的啟用“ tostring() ”對象視圖 2.代碼和hdfs路徑都對的情況下&#xff0c;程序…

架構設計系列之基礎:初探軟件架構設計

11 月開始突發奇想&#xff0c;想把自己在公司內部做的技術培訓、平時的技術總結等等的內容分享出來&#xff0c;于是就開通了一個 Wechat 訂閱號&#xff08;灸哥漫談&#xff09;&#xff0c;開始同步發送內容。 今天&#xff08;12 月 10 日&#xff09;也同步在 CSDN 上開通…

文章解讀與仿真程序復現思路——電力系統自動化EI\CSCD\北大核心《面向微電網群的云儲能經濟-低碳-可靠多目標優化配置方法》

這篇文章的標題涵蓋了以下關鍵信息&#xff1a; 面向微電網群&#xff1a;研究的重點是微電網群&#xff0c;這可能指的是多個微電網系統的集合&#xff0c;而不僅僅是一個單獨的微電網。微電網是指由分布式能源資源、儲能系統和智能控制組成的小型電力系統&#xff0c;通常能夠…

記錄每日LeetCode 406.根據身高重建隊列 Java實現

題目描述&#xff1a; 假設有打亂順序的一群人站成一個隊列&#xff0c;數組 people 表示隊列中一些人的屬性&#xff08;不一定按順序&#xff09;。每個 people[i] [hi, ki] 表示第 i 個人的身高為 hi &#xff0c;前面 正好 有 ki 個身高大于或等于 hi 的人。 請你重新構…

《C++新經典設計模式》之附錄A 類和對象

《C新經典設計模式》之附錄A 類和對象 A.1 靜態對象的探討與全局對象的構造順序A.1.1 靜態對象的探討A.1.1.cpp A.1.2 全局對象的構造順序問題A.1.2.cpp A.2 拷貝構造函數和拷貝賦值運算符A.2.1 拷貝構造函數和拷貝賦值運算符的書寫A.2.1.cpp A.2.2 對象自我賦值產生的問題A.2.…

實現加鹽加密方法以及java nio中基于MappedByteBuffer操作大文件

自己實現 傳統MD5可通過彩虹表暴力破解&#xff0c; 加鹽加密算法是一種常用的密碼保護方法&#xff0c;它將一個隨機字符串&#xff08;鹽&#xff09;添加到原始密碼中&#xff0c;然后再進行加密處理。 1. 每次調用方法產生一個唯一鹽值&#xff08;UUID &#xff09;密碼…

UDS診斷 10服務

文章目錄 簡介診斷會話切換請求和響應1、請求2、子功能3、肯定響應4、否定響應5、特殊的NRC 為什么劃分不同會話報文示例UDS中常用 NRC參考 簡介 10服務&#xff0c;即 Diagnostic Session Control&#xff08;診斷會話控制&#xff09;服務用于啟用服務器中的不同診斷會話&am…

(四) python門面模式

文章目錄 4.1 結構型設計模式4.1.1 簡介4.1.2 常見的幾種結構型設計模式 4.2 理解門面設計模式4.2.1 門面設計模式概述4.2.2 門面設計模式的作用 4.3 UML類圖4.3.1 門面4.3.2 系統4.3.3 客戶端 4.4 門面模式的代碼實現4.4.1 場景&#xff1a;4.4.2 python實現 4.5 原理&#xf…

Compose for iOS:kotlin 與 swift 互操作

前言 類似于 Android 上的 compose&#xff0c;在 iOS 上的 compose 同樣支持嵌套顯示 compose UI 和 swiftUI 或是 uikit 。 但是不同于 Android 原生就是使用 kotlin 作為開發語言&#xff0c;iOS 的開發語言是 swift 或者 object-c 。雖然大多數業務邏輯都可以直接使用 ko…

渲染(iOS渲染過程解析)

渲染 渲染原理 一個硬核硬件科普視頻 CPU和GPU CPU&#xff08;Central Processing Unit&#xff09;&#xff1a;現代計算機整個系統的運算核心、控制核心&#xff0c;適合串行計算。GPU&#xff08;Graphics Processing Unit&#xff09;&#xff1a;可進行繪圖運算工作的…

安防音頻接口選型的高性能國產芯片分析

在人工智能興起之后&#xff0c;安防市場就成為了其全球最大的市場&#xff0c;也是成功落地的最主要場景之一。對于安防應用而言&#xff0c;智慧攝像頭、智慧交通、智慧城市等概念的不斷涌現&#xff0c;對于芯片產業催生出海量需求。今天&#xff0c;我將為大家梳理GLOBALCH…

springboot_3.2_freemark_基礎環境配置

springboot_3.2_freemark_基礎環境配置 一、前言二、環境三、相關資料四、目標五、默認配置項六、構建springboot 3.2項目6.1 pom.xml 內容&#xff1a;6.2 啟動類6.3 添加ftlh模板6.4 controller內容6.5 bootstrap.yml配置 七、總結 一、前言 FreeMarker 是一款模板引擎&…

Linux——緩沖區與實現C庫的fopen,fwrite,fclose

目錄 一.緩沖區 1緩沖區的概念 2.緩沖區存在的意義 3.緩沖區刷新策略 4.什么是刷新&#xff1f; C語言的緩沖區在哪里&#xff1f; ?編輯 仿寫C庫里的fopen&#xff0c;fclose&#xff0c;fwrite。 mystdio.h mystdio.c main.c(向文件中寫入20次msg) 一.緩沖區 1…

b站pwn的學習總結

寫的很亂 1.c語言的運行過程 了解了c語言需要經過以上2個過程&#xff08;編譯和匯編&#xff09;&#xff0c;才能讓機器按指令運行。機器只能聽得懂機器碼&#xff0c;所以要“匯編”。 那問題就來了&#xff0c;“編譯”這個動作有啥用&#xff0c;c語言這種高級語言&…