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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

求最长回文串-从动态规划到马拉车之路(上)

發(fā)布時(shí)間:2025/3/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 求最长回文串-从动态规划到马拉车之路(上) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

要解決的問題:

給定一個(gè)字符串,要求求出這個(gè)字符串中的最長(zhǎng)的回文串子串。

例子:

cbddba的最長(zhǎng)回文子串為 bddb

cbdedba的最長(zhǎng)回文子串為dbedb

由上面的例子可以看到,在考慮回文子串的問題時(shí)需要考慮奇偶性。因?yàn)槠婊匚年P(guān)于中心的某個(gè)字符對(duì)稱,而偶回文關(guān)于最中心的兩個(gè)元素之間的間隙對(duì)稱。

一、動(dòng)態(tài)規(guī)劃法

在動(dòng)態(tài)規(guī)劃的思想中,總是希望把問題劃分成相關(guān)聯(lián)的子問題;然后從最基本的子問題出發(fā)來(lái)推導(dǎo)較大的子問題,直到所有的子問題都解決。

首先要看一個(gè)較大的子問題與一個(gè)較小的子問題之間的關(guān)系:

首先建立如下的函數(shù):


那么就能有如下的遞推關(guān)系:

當(dāng)p(i+1,j-1)? = true 的時(shí)候,如果有si == sj,那么 p(i,j)=true;也就是 abba中的bb為回文串,那么在bb左邊是a,在bb右邊也是a,相同;所以有abba也是回文串。

形式化表示如下: p(i,j) = p(i+1,j-1) and si==sj? ? 這就建立了較大問題與較小問題之間的關(guān)系。

然后考慮基本情況,一個(gè)最基本的回文串有兩種情況(奇偶性):

(1) 最基本的奇回文,只有一個(gè)字符,而且恒成立;形式化表示為 p(i,i) = true

(2)最基本的偶回文,有兩個(gè)字符,當(dāng)且僅當(dāng)兩個(gè)字符相等的時(shí)候成立p(i,j) = (si==sj and j=i+1)

最后獲得如下判斷一個(gè)字符是否為回文串的分段函數(shù):


有了公式,就是用代碼實(shí)現(xiàn)了;下面給出了我的python實(shí)現(xiàn)。

# -*- coding:utf-8 -*- # Author: Evan Mi# 測(cè)試的字符串 str_exp = "babad" # 用來(lái)保存動(dòng)態(tài)規(guī)劃過程的表 1表示true 0表示false longest_palindromes = [[-1] * len(str_exp) for i in range(len(str_exp))] # longest_len 用來(lái)保存最長(zhǎng)的回文串的長(zhǎng)度 longest_len = 1 # 從長(zhǎng)度為1的回文子串開始填表 for p_len in range(1, len(str_exp)+1):for i in range(len(str_exp)):j = p_len + i - 1if j < len(str_exp):if i == j:longest_palindromes[i][j] = 1elif j == i + 1 and str_exp[i] == str_exp[j]:longest_palindromes[i][j] = 1longest_len = p_lenelif j > i+1 and longest_palindromes[i+1][j-1] == 1 and str_exp[i] == str_exp[j]:longest_palindromes[i][j] = 1longest_len = p_lenelse:longest_palindromes[i][j] = 0 # 搜索結(jié)果表,打印出所有的最優(yōu)解 for i in range(len(str_exp)):for j in range(len(str_exp)):if longest_palindromes[i][j] == 1 and j-i+1 == longest_len:print(str_exp[i:j+1])

在動(dòng)態(tài)規(guī)劃中,最最最核心的就是填表了,就以程序中的例子"babad"舉例,說(shuō)明一下填表的過程;

首先我們要填的表是如下的一張表二維表(因?yàn)閜函數(shù)中有i,j兩個(gè)變量),其中綠色的部分是真實(shí)的表格,其他的是我家的解釋表頭。


填表過程如下:首先填長(zhǎng)度為1的;

?

???然后填長(zhǎng)度為2的;

?

???接著是長(zhǎng)度為3的:


??長(zhǎng)度為4的:


??最后是長(zhǎng)度為5的:


填表完成之后,求最優(yōu)解就是查詢了;對(duì)于時(shí)間復(fù)雜度,動(dòng)態(tài)規(guī)劃的時(shí)間復(fù)雜度在構(gòu)建表的過程中的基本操作,所以時(shí)間復(fù)雜度是O(n^2);空間復(fù)雜度,就是上面的二維數(shù)組,也是O(n^2)。而且從在空間浪費(fèi)(主對(duì)角線下面的空間沒有使用,浪費(fèi)了一般的空間)。有很多針對(duì)空間上的優(yōu)化方法,下面給出一種空間復(fù)雜度為O(1)的算法;


二、空間復(fù)雜度為O(1)的算法


該算法的主要思想就遍歷所有的字符(下標(biāo)為i)是以第i個(gè)數(shù)(對(duì)應(yīng)奇回文)或者第i個(gè)數(shù)和第i+1個(gè)數(shù)之間的間隙(對(duì)應(yīng)偶回文)為中心向兩邊擴(kuò)展,直到擴(kuò)展以后不再是回文,那么就停止擴(kuò)展,如果回文長(zhǎng)度比已知的最長(zhǎng)回文長(zhǎng),那么記錄下該回問的開始位置和結(jié)束位置為最長(zhǎng)回文;

還是用"babad"來(lái)作為例子,過程如下:



代碼實(shí)現(xiàn)如下:

# -*- coding:utf-8 -*- # Author: Evan Mi import mathdef expandAroundCenter(left, right, s):"""從left和right之間開始擴(kuò)展,如果left==right就是以left/right為中心進(jìn)行擴(kuò)展"""rLeft = leftrRight = rightwhile rLeft >= 0 and rRight < len(s) and s[rLeft] == s[rRight]: # 進(jìn)行擴(kuò)展rLeft -= 1rRight += 1"""針對(duì)于返回的長(zhǎng)度,因?yàn)樵趙hile循環(huán)停止的時(shí)候,rLeft和rRight都已經(jīng)在要求的回文串之外了所以回文串的長(zhǎng)度為rRight - rLeft - 1,自己可以畫個(gè)過程圖,一目了然。"""return rRight - rLeft - 1s = "babad" start = 0 end = 0for i in range(len(s)):odd_len = expandAroundCenter(i, i, s) # i為中心的擴(kuò)展even_len = expandAroundCenter(i, i + 1, s) # i 和 i+1之間的空隙為中心進(jìn)行擴(kuò)展lens = max(odd_len, even_len) # 取得本次擴(kuò)展的最大值if lens > (end-start+1): # 如果本次的長(zhǎng)度比記錄的回文的長(zhǎng)度也就是end-start+1大,進(jìn)行替換# 需要注意的是,已經(jīng)知道了位置i,不管是以i為中心擴(kuò)展了長(zhǎng)為lens的回文還是# 以i和i+1的空隙為中心擴(kuò)展了長(zhǎng)為lens的回文。下面的start和end的計(jì)算方法都成立start = i - math.floor((lens - 1) / 2) end = i + math.floor(lens/2)print(start, ":", end) print(s[start:end+1])


這里時(shí)間復(fù)雜度并沒有改變,但是我們的空間復(fù)雜度變成了O(1)。但是也帶來(lái)了明顯的缺陷,那就是只能求的第一個(gè)出現(xiàn)的最優(yōu)解。 額,如果把 if lens > (end-start+1) 改為 if lens >= (end-start+1),那么能求最后出現(xiàn)的最優(yōu)解。

這兩個(gè)算法不論在空間、結(jié)果上有什么不同,它們的時(shí)間復(fù)雜度都是相同的;接下來(lái)就分析一下“馬拉車”算法,該算法把時(shí)間復(fù)雜度降到了線性范圍內(nèi)。額,請(qǐng)見下篇博客。

PS:很多人都分析了"馬拉車"算法,但是也阻擋不了我征服它的步伐。相信自己對(duì)它一定有獨(dú)到的見解。

總結(jié)

以上是生活随笔為你收集整理的求最长回文串-从动态规划到马拉车之路(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。