最長公升 降 不公升 不降子串行 模型 解決及擴充套件應用

2021-07-09 22:58:40 字數 2654 閱讀 7410

【最長公升/降/不公升/不降子串行:模型】

簡單來說,標題中所說的最長公升/降/不公升/不降子串行這四種型別,都可以概括成一句話。就是對於這個被選出的子串行中的每乙個元素,都大於/小於/不小於/不大於子串行中的前乙個元素。如果設原來的序列為a,被選出的子串行為b,並且我們用compare(u,v)來表示子串行中的前後滿足關係(即當compare(u,v)為真時,v可以在子串行中在u的後面),那麼我們將關係概括成下面這樣 :

而最長公升/降/不公升/不降子串行就是將b的長度最大化,注意b可能不唯一,所以說一般只需要輸出長度。

【最長公升/降/不公升/不降子串行:解決】

【解法1:搜尋】

很容易想到,我們完全可以列舉,利用乙個指數級的搜尋,2^n地列舉某個元素是放還是不放,那麼再加乙個檢查過程,就很容易證明其正確性。

【解法2:動態規劃的暴力】

我們很容易發現解法1的計算有相當的冗餘的計算,所以,怎樣優化呢?答案應該從動態規劃入手,利用子問題的劃分,來減少冗餘的計算。對於每乙個a中的元素,我們都有兩種策略:放和不放,所以容易看出dp的方程:

這個演算法足夠高效了。某種意義上來說,可能沒有更好的演算法了,或者說其他演算法的時間複雜度和這個演算法或者其的優化版相當。動態規劃的高效之處,就在於將子問題大量重疊的情況全部歸類,利用子問題,將重複的計算省去,這樣我們就可以得到乙個**可能只有二三十行的短小精悍的高效程式。

回到原來的問題,我們下面來說明這個演算法的正確性。以最長(上)公升序列為例,首先,對於每乙個f(i),我們都應該在其前面找乙個f(j),使得f(i)可以「接上」f(j),那麼如果沒有呢?也就是說,當前的這個元素比前面所有元素都要小呢?那麼我們就將這個元素設為1,或者我們更好的方法是加乙個哨兵,比如在最前面加乙個

那麼我們怎麼實現呢?我們很容易想到暴力的方法,就是直接乙個乙個去尋找符合條件的j並且去比較就好了,時間複雜度為

【解法3:動態規劃的高數(高階資料結構)優化】

我們如果遇到一些苛刻的題目,資料量很大,用普通的演算法過不了,那麼我們應該怎麼辦?答案是:優化。在這裡我們就可以使用線段樹來優化,當然樹狀陣列也可以。

動態規劃的思想部分我就不講了,主要的困難就在於怎樣實現,使得在j考慮了之後才考慮i,而且找到f(j) ,使其最大。這就是我們要找的重點所在。要求的最大值很容易想到線段樹,可是怎樣使得

但是注意到有可能ai會很大,那麼我們的一大工具離散化就又出場了。下面是整個演算法的描述:先加個哨兵,再將a中陣列排序後放到c中,並且將a中和c中元素都將其原來的和現在的編號全部打上去,將每乙個元素的f值全部設為0,接著依次考慮每乙個a中的元素,找到其在c中的元素,利用線段樹或樹狀陣列找到c中那個元素前面的所有元素的f的最大值,並且加1後就作為當前這個元素的f值。

忽略掉線段樹之後**真的不長……不過這個演算法用樹狀陣列或許更是個不錯的選擇,因為這裡要求的區間類似於字首和的模型,用樹狀陣列去維護這種有限制的字首類區間最值會比較方便。至於時間複雜度,容易看出來是

【解法4:動態規劃的單調性優化】

下面再來介紹乙個神奇的演算法:利用單調性,使用二分查詢優化的演算法。雖然時間複雜度一樣,但是容易寫了很多,而且常數也小了。

剛才,我們是以高度作為下標,那麼我們看一看用其他的東西作為下標怎樣?比如說,子串行的長度?這就是我們要的這種神奇的演算法。以f作為下標。我們設為d陣列。但是我們考慮一下,可能會有很多的f相同的元素,那麼我們選哪乙個呢?答案是:那個越有利,就選哪個。繼續以最長(上)公升序列為例,我們就應該選擇相應的a值最小的乙個。因為這樣才可能讓更多的元素能夠連線上這個d中的f。容易看出,d是單調不降的。

那麼,演算法也出來了:首先,同樣是加個哨兵,然後對於所有a中的元素i,二分查詢出d中最後乙個(嚴格)小於ai的元素,然後將這個元素連上i,也就是說,設這個元素為f(j),那麼f(i)=f(j)+1。接著,我們就去更新相應的f即可。

要證明其的單調性,我們用類似遞推的方式(我忘記這叫什麼方法了),首先一開始高度必然是單調不降的,然後每一次我們放進去乙個元素,如果這個元素i後面的乙個u要比這個i的高度低,就是說原來的ai【擴充套件應用】

由於暫時沒有時間,馬上就要過年了,我就只講乙個最長公共子串行的問題。

最長公共子串行的定義我就不講了,就是說在兩個序列a和b中分別選取若干個元素,使得這些若干個元素以在各自原來的序列中的位置排成的兩個序列相同,並且長度最長。比如說「aab」就是「acaab」的子串行。

那麼,怎樣高效地求這樣的乙個最長公共子串行呢?如果我們要求長度的話,我們還是可以用最長上公升子串行來做。我們先假定a中沒有重複的元素,那麼我們順序將a中元素標為1,2,3,4……n,然後將b中的元素依次按照這樣的標號標出來。比如說a中有乙個'd'標為了8,那麼b中的所有『d'都得標上8。接著我們對b這個經過處理的標號進行一次最長上公升子串行就好了。想想看,我們可以找出來乙個重大的發現,就是b中的乙個上公升子串行,對應著a中的乙個子串行,而且這兩個子串行的內容完全相同!想想也很容易理解,因為子串行的定義就是要下標遞增,那麼b中的所有子串行都是下標遞增的;而由於每乙個的標號都對應著a中的乙個字元,那麼我們應該想到,由於我們考慮的這個上公升子串行的標號都是上公升的,那麼由於標號對應著a中的下標,那麼其對應的a中下標也是遞增的!接著,只有a和b中相同的字元有相同的標號,那麼我們也可以發現,這兩個對應的子串行完全相同!所以只需求乙個最長上公升子串行即可。

不過這裡還有一點問題,那就是:如果有乙個字元,只在b中有怎麼辦(就是說找不到對應的a中標號)?那麼我們最簡單的處理辦法就是:不管它!因為這個字元值在b中有,所以說不可能在公共子串行中存在,因此忽略即可。

這就是最長公升/降/不公升/不降子串行,可擴充套件的其實還有很多,這裡就不一一細講了。

最長不降子串行

原文 這題目是經典的dp題目,也可叫作lis longest increasing subsequence 最長上公升子串行或者 最長不下降子串行。很基礎的題目,有兩種演算法,複雜度分別為o n logn 和o n 2 一 問題描述 設有由n個不相同的整數組成的數列,記為 a 1 a 2 a n 且...

最長不降子串行問題

一 問題 輸入 設有由n個不相同的整數組成的數列,記為 a 1 a 2 a n 且a i a j i j 若存在i1長度為e的不下降序列。輸出 程式要求,當原數列給出之後,求出最長的不下降序列。例子 數列3,18,7,14,10,12,23,41,16,24。3,18,23,24就是乙個長度為4的不...

最長不降子串行 dp

問題描述 給定乙個字串,求出其不降子串行的最大長度。分析 從後往前逆推 06對於n個數,我們可以分為n 1個階段。07我們由後向前搜尋 逆推法 我們可以這樣思考 081 對a n 來說,由於它是最後乙個數,所以當從a n 開始查詢時,只存在長度為1的不下降序列 092 若從a n 1 開始查詢,則存...