回文字符串問題分析

2021-01-20 九點微報

回文字符串,是指正讀和倒讀的結果一樣的字符串,從結構上來看,兩側的字符呈中心對稱。在漢語中,有很多有趣的迴文詩詞,回文對聯熟語,比如「響水池中池水響,黃金谷裡谷金黃」、「霧鎖山頭山鎖霧,天連水尾水連天」等。根據其結構特徵,我們很容易設計出一個判斷字符串是否回文的算法:

isPalindromic(s)boolean flag=truechar[] chars=s.toCharArray()for i=0 to (chars.length-1)/2if chars[i]!=chars[chars.length-1-i] flag=false breakreturn flag

現在我們看一道leetcode中關於取一個字符串中最長的回文字的問題:

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

首先最簡單的方法,暴力窮舉所有的子串,然後分別利用上述的方法進行判斷即可。遍歷+判斷,窮舉法總的時間複雜度為O(n^3).

bruteForceForPalindromic(S)String resultfor i=0 to s.length()-1for j=i+1 to s.length()-1 substring=s.substring(i,j) if(isPalindromic(substring) and substring.length()<result.length()) result=substring

很顯然,上述暴力算法在運行效率上是極低的。主要原因是其存在著大量重複的判斷,比如當substring(i,j)不是回文串時,我們可以確定substring(i-1,j+1)一定不是回文串,不用進行判斷即可。由此我們考慮構造一個從中心節點雙向探測的方法來獲取最長的回文子串,即判斷每一個中心節點可以構成的回文的最長串。現在的主要問題是,一共有多少個這樣的中心節點呢?答案是2*n-1個,這是考慮了奇數回文和偶數回文的兩種不同情況,如下圖所示。

/*** 以每一個點為中心點,向兩邊探測的方法判斷回文 * @param s * @return */ private static String getLongestPalindromic1(String s) { String result = ""; String sub = ""; char[] chars = s.toCharArray(); int n = s.length(); int j = 0; //以此以每一個字符作為回文的中心節點centercode for (int i = 0; i < n; i++) { //奇數回文探測 j = 0; while (j <= i && i + j < n && chars[i - j] == chars[i + j]) { sub = s.substring(i - j, i + j + 1); j++; } result = result.length() < sub.length() ? sub : result; //偶數回文探測 j = 0; while (j <= i && i + j + 1 < n && chars[i - j] == chars[i + j + 1]) { sub = s.substring(i - j, i + j + 2); j++; } result = result.length() < sub.length() ? sub : result; } return result; }

對於當個字符來說,其本身認為是回文的,則可以得到dptablei=true;

最後我們考慮動態規劃的基礎值的情況:

首先我們使用一個布爾類型的二維數組dptablen來表徵第i個字符到底j個字符構成的子串是否回文,構成則值為true,否則為false。考慮到對於回文子串substring(i+1,j-1)若且唯若s[i]==[j]時,可以得到substring(i,j)是回文的。現在可以根據這樣的性質去構造遞推關係:

對於當個字符來說,其本身認為是回文的,則可以得到dptablei=true;

對於相鄰的兩個字符來說,如果兩個字符是相等的,則認為其是回文的,否則不構成回文,所以dptablei=s[i]==s[i+1]。

綜合上述的討論,算法的時間複雜度為O(n^2)。Java實現如下:

/*** 動態規劃的方法求解最長回文子串 * @param s * @return */ private static String getLongestPalindromicDP(String s) { String result = ""; char[] chars = s.toCharArray(); int n = chars.length; boolean[][] dptable = new boolean[n][n]; //初始化動態規劃數組 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { dptable[i][j] = false; } } //設置規劃的base值 for (int i = 0; i < n; i++) { dptable[i][i] = true; } for (int i = 0; i < n - 1; i++) { if (chars[i] == chars[i + 1]) { dptable[i][i + 1] = true; } } //規劃計算 for (int j = 2; j < n; j++) { for (int i = 0; i < j - 1; i++) { dptable[i][j] = dptable[i + 1][j - 1] && (chars[i] == chars[j]); } } //取得最長的回文串 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (dptable[i][j] == true) { result = result.length() <= j - i ? s.substring(i, j + 1) : result; } } } return result; }

相關焦點

  • 回文子串劃分(基礎DP)- UVA 11584
    正序倒序寫都相同的字符串我們稱之為回文串。例如,『racecar』就是回文的,『fastcar』就不是。對一個字符序列的劃分即:分成一堆(至少一個)非空不相交的連續字符串,使它們連起來就是原來的字符序列。例如,『race』,『car』就是把『racecar』劃分成兩組。給定一個字符串,我們總能找到一種劃分使得每個子串都是回文串!
  • 深入剖析go中字符串的編碼問題——特殊字符的string怎麼轉byte?
    問題原問題我就不碼字了,直接上圖:看到問題,我的第一反應是ASCII碼值範圍應該是0~127呀,怎麼會超過127呢?沒有經過字節級別的轉義,那麼字符串是一個標準的utf8序列。有了前面的基礎知識和字符串是一個標準的utf8序列這一結論後我們接下來對字符串「」(如果無法展示,記住該特殊字符的unicode是\u0081)手動編碼。
  • 用Python求最長子串長度快速版
    哈嘍大家好,周二也是令人愉快的一天啊,今天天氣不錯,坐在窗戶旁邊邊曬太陽邊寫文章,再泡杯熱茶,真是舒服美好,廢話不多說,今天說一下Python求最長子串長度,希望對大家有作用,raksmart伺服器。給定一個字符串,求它最長的回文子串長度,例如輸入字符串'35534321',它的最長回文子串是'3553',所以返回4。
  • Python中如何分割、合併字符串
    第七十四節:分割、合併字符串字符串可以通過分割操作,劃分成一個個小個體;也可以用過合併操作,重新組成一個完整的字符串。2、合併字符串既然在Python中字符串可以分割,那麼它也提供了一個join()方法可以合併字符串,它的格式是下面這樣的:newstr = string.join(iterable)
  • C語言|字符串數組的初始化
    用字符串初始化2. 用單個字符初始化在這裡我們可以看到,存儲「hello」的字符串數組的大小應該至少為6的,但這裡我們發現把數組的大小設為5,程序也可以正常運行,如下圖所示。再小了就會報錯了但是,在用第一種方法,即直接用字符串賦值的時候卻要嚴格遵守字符串數組的大小規則此時程序報錯,有知道這是為什麼的朋友可以留言或者私信我在插入了』\0』之後,字符串就結束了也可以在其中插入回車符來實現換行的效果
  • 你真的知道 Python 字符串怎麼用嗎?
    前面已說過,字符串是不可變序列,所以字符串拆分過程是在拷貝的字符串上進行,並不會改變原有字符串。split() 方法可接收兩個參數,第一個參數是分隔符,即用來分隔字符串的字符,默認是所有的空字符,包括空格、換行(\n)、制表符(\t)等。拆分過程會消耗分隔符,所以拆分結果中不包含分隔符。
  • 20.表示數值的字符串(劍指 Offer 題解,面試遇到好多次)
    例如,字符串"+100",「5e2」,"-123",「3.1416"和」-1E-16"都表示數值。但是"12e",「1a3.14」,「1.2.3」,"±5"和"12e+4.3"都不是。false「12e」「1a3.14」「1.2.3」「±5」「12e+4.3」思路思路一:利用正則表達式,對字符串中的每個字符進行判斷分析
  • Python中去除字符串首尾空格、特殊字符和指定子字符串的方法
    去除字符串首尾空格和特殊字符從上面的實例可以看出,在Python的IDLE中,定義好一個字符串後,直接使用字符串變量名回車,就會輸出包含特殊字符的字符串;使用print()函數輸出字符串時,其中的特殊字符「\n、\r、\t」則被默認為命令執行了;使用strip()方法,只能去除字符串首尾的空格和特殊字符,存在於字符串中間的空格和特殊字符是無法去除的。
  • Python 格式化字符串的最佳姿勢
    對於用 Python 處理數據和文本的同學一定經常要和字符串格式化打交道
  • JAVA 中如何反轉字符串字符,一共4中方式,請牢記!
    比如:String str = "abcd";通過反轉倒序後輸出:dcba故此文本主要講述如何將 String 類型的字符串字母倒序過來的幾種方法。下面就列舉如下4種方法並一一說明!其實也很簡單,通過如下幾步即可:將字符串轉為 char[]數組逐個循環 char[]數組使用 temp 變量進行值交換上面的源碼算法實現需要5個循環(長度/ 2)來使字符串倒序
  • 魔獸世界:六串神秘「字符」,玩了多年魔獸,還是沒搞懂啥意思
    隨後又有許多玩家開始尋找,暴雪為什麼要在這把武器上印刻「AL」這樣的字符,最後依舊是眾說紛紜,這串神秘的字符,就成為了這把武器最形象的代表!第二串神秘字符:介紹面板上的神秘「亂碼」如果你玩過諾莫瑞根這個副本,肯定看到過上面這個一個介紹面板,這個面板上,有一串非常神秘的字符(這串字符,是用0和1排列的),第一次見到這樣的字符的時候,還一度認為是我的電腦出了問題
  • 《第2章 Python 語法基礎》2.3.2 字符串!
    《高中信息技術 Python編程》 教學案 《第2章 Python 語法基礎》2.3.2 字符串!瀏覽器版本過低,暫不支持視頻播放2.3.2、字符串:字符串是連續的字符序列,可以是計算機所能表示的一切字符的集合,屬於不可變序列。
  • 一段神秘字符讓 iPhone 瞬間崩潰
    似乎每隔一段時間,網上就會曝出一個能讓 iOS 系統崩潰的字符串,這些字符串大都是我們平時不常用也不常見的特殊字符,一旦接收到帶有特殊字符的消息時,就會讓 iPhone 瞬間崩潰。 最近,國外網友就又發現了一個神秘字符,並迅速在社交網絡上流行起來。
  • 我擦~字符串轉字節切片後,切片的容量竟然千奇百怪
    >分析到這兒我已經滿腦子問號了字符串變量轉切片一個小小的字符串轉切片, 內部究竟發生了什麼, 竟然如此的神奇。abc"(SB), AX // 將字符串"abc"放入寄存器AX0x0036 00054 (test.go:6) MOVQ AX, "".a+96(SP) // 將AX中的內容存入變量a中0x003b 00059 (test.go:6) MOVQ $3, "".a+104(SP) // 將字符串長度3存入變量a中0x0044 00068 (test.go:7) MOVQ $0
  • 讓iPhone手機崩潰的神秘字符又出現了!
    並且這次中招的不僅僅只有iPhone,蘋果旗下的產品包括Mac和AppleWatch都沒能倖免,只要收到這串字符都能觸發這個bug直接讓系統崩潰。並且這位老哥還上傳了自己的iPhone收到字符後崩潰的情況,根據爆出的視頻顯示,iPhone在複製字符之後,在卡頓幾秒就直接死機,怎麼觸摸都沒反應。留言區裡,這串神秘字符大量出現。
  • 蘋果設備收到這串字符會死機,只能強制重啟
    中國經濟周刊-經濟網訊 4月24日,據推特帳號Everything Apple Pro爆料,當iPhone、iPad、Mac等設備收到一串字符時,會導致設備死機,該串字符由信德語和義大利國旗的emoji組成(可以不需要國旗符號),它可以通過任何APP傳播。
  • 好玩的英語 | 英語中的「回文」現象
    最近不少人去看了諾蘭新片《信條》,有懷疑自己智商的,有分析劇情的。不過你有注意到此片的英文片名嗎?Tenet,從構詞角度看,這是一個回文單詞。回文是什麼?英文中叫Palindrome。先不要被這個高深莫測的術語給嚇到。這句中文句子你應該見過:上海自來水來自海上。
  • 【詩詞微塾】詩詞創作之迴文詩結構
    本文試圖從語言文字的結構分析去探索迴文詩(類似「文字遊戲」,饒有趣味)的基本特點,試圖幫助青年讀者學習詩詞格律。 蘇軾有《題織錦回文》詩曰: 春晚落花餘碧草,夜涼低月半梧桐。 人隨雁遠邊城暮,雨映疏簾繡閣空。
  • Java 字符編碼
    JVM 屏蔽了大小端問題,默認為大端,並且可使用 ByteOrder.nativeOrder()查詢處理器和內存系統的大小端,在使用 ByteBuffer 時,也可以使用 ByteBuffer.order()進行設置。BOMUnicode 的學名是 "Universal Multiple-Octet Coded Character Set",簡稱為 UCS。