動態規劃專題學習

2021-10-07 20:04:54 字數 3579 閱讀 9722

一.明確dp陣列的含義

構造一維dp[i]、二維dp[i][j],明確其代表了什麼狀態,一般與題目的目的有關。如解決萬用字元問題,就定義boolean dp表示s[i-1]與p[j-1]的匹配成功與否;解決最長子陣列問題,就定義dp表示a[i-1]與b[j-1]的最長字尾公共陣列長度;解決最長子序列問題,就定義dp表示a[i-1]與b[j-1]的最長公共序列長度。

二.定義base case基本值

dp[0][j]與dp[i][0]表示什麼情況,有時預設為0,有的情況需要初始化

如萬用字元問題dp[0][j]表示主串為0模式串不為0的情況下,*可以使其為true,dp[i][j]表示主串不為0模式串為0,一律為false,而dp[0][0]=true

而在最長公共子陣列/子串行問題中預設初始都為0

三.尋找狀態轉移方程/繼承關係

關鍵一步:已知上一步的狀態,如何求當前狀態值。

在萬用字元問題中分情況討論,a與a/b ,a與?,a與*,』 '與*四種情況

在子陣列問題中,當前字元相等則count+1,否則為0

在子串行問題中,當前字元相等則count+1,否則繼承a[i-1]b[j]或a[i]b[j-1]的較大值。

最後返回最終狀態即可。

動態規劃可以解決的問題:

型別1:兩個字串/陣列之間的某種關係,如最長公共子串,最長公共子序

列,兩字串匹配…

型別2:路徑規劃方案 leetcode 66 路徑之和

leetcode 44 字串的通配

* :任意長度字串(可為0)

?:單個字元

【分析思路】

假設主串a的長度為n,模式串b的長度為m,比較的情況有如下幾種:

1.如果b的位置上為普通字元,則比較兩個字元是否匹配,相等則繼續向前比較 a[n-2]與b[m-2]

2.如果b位置上為?,則跳過比較a[n-1],向前比較a[n-2]與b[m-2]

3.如果b位置上為*,的作用分為2種:

①匹配0個a字元,下一步比較a[n-1]與b[m-2],即b向前走一步,a不動

②匹配多個a字元,下一步比較a[n-2]與b[m-1],即a向前走一步,b不動

【轉移方程】

f[i][j]代表a的前i個和b的前j個字元能否匹配

·對於情況1和2,合併 f[i][j] = f[i-1][j-1]

·對於情況3:

①a不動,b動,跳過b的,向前繼承:f[i][j] = f[i][j-1]

②a動,b不動,*的作用還可以保留在下一次使用,向前繼承:

f[i][j] = f[i-1][j],這裡的b[j]還是 ,仍可匹配多次

邊界情況:

① dp[0][0]=true,即當字串s和模式p均為空時,匹配成功;

② dp[i][0]=false,即空模式串無法匹配字串

③ dp[0][j],看p前面有幾個就匹配多少空字元,**3:true,true,false

【**】

// 動態規劃 dp[i][j]表示s(i)和p(j)前的字串的能否匹配上

public

static

boolean

ismatch

(string s, string p)

else

}for

(int i =

1; i <= m;

++i)

else

if(p.

charat

(j -1)

=='?'

|| s.

charat

(i -1)

== p.

charat

(j -1)

)}}return dp[m]

[n];

}

leetcode 718 最長公共/重複子陣列

給出兩個整數陣列a和b,返回兩個陣列中公共的、最長的子陣列

[暴力搜尋]

ans = 0

for i in [0 .. a.length - 1]

for j in [0 .. b.length - 1]

k = 0

while (a[i+k] == b[j+k]) do # and i+k < a.length etc.

k += 1

end while

ans = max(ans, k)

end for

end for

如何優化? 暴力搜尋進行了重複比較,為了只比較一次,用動態規劃記錄當前位置的兩個字串最長公共字尾陣列,進行狀態轉移

dp[i][j]表示a[i-1]前的陣列中與b[j-1]前的陣列中的最長公共長度(必須包含末尾數字,即以a[i-1],b[j-1]為字尾的最長子陣列)

[狀態轉移方程]

若a[i-1]==b[j-1],則dp[i][j] = dp[i-1][j-1] + 1;

否則dp[i][j] = 0;

//leetcode 718動態規劃解決最長公共子陣列

public

static

intmaxcommonsubarray

(int

a,int[

] b)

max = math.

max(max,dp[i]

[j]);}

}return max;

}

leetcode 1143 最長公共/重複子序列

兩個字串的最長公共子串行 序列是指:「ace」 是 「abcde」 的子串行,即在不改變順序的情況下可以忽略某些字串

因為子串行型別的問題,窮舉出所有可能的結果都不容易,而動態規劃演算法做的就是窮舉 + 剪枝,它倆天生一對兒。所以可以說只要涉及子串行問題,十有**都需要動態規劃來解決,往這方面考慮就對了。

[狀態轉移]

思路:理清楚當前狀態如何繼承上乙個狀態

當比較到dp[i][j]位置時,對於a[i-1]與b[j-1],

若a[i-1]=b[j-1],則繼承dp[i-1][j-1] + 1

若a[i-1]!=b[j-1],則取a[i-2]&b[j-1]或a[i-1]&b[j-2]比較結果的較大值繼承:因為當前不等,就取前面子串行的最大值繼承max(dp[i-1][j],dp[i][j-1])。

【**】

public

intlongestcommonsubsequence

(string text1, string text2)

else}}

return dp[len1]

[len2]

;}

可見最長公共子陣列和最長公共子串行的思路一致,細節不同在於寫狀態轉移方程時如何繼承上乙個狀態值。

子陣列的問題在於若比較的字元不同,則公共長度為0(以其為字尾)

子串行的問題在於若比較的字元不同,則公共長度繼承之前子串行的最大值

專題學習 LCT

等下發樹剖的學習筆記 lct link cut tree 是解決一類動態樹問題的資料結構 主要是給乙個有根樹的森林,然後有動態插入邊,刪除邊,詢問等操作 保證時刻是乙個森林 lct維護子樹資訊比較麻煩,這裡暫時不提 一 實邊和虛邊 lct 會將兒子劃分為虛 實兩種兒子,相應的邊稱為虛邊或實邊,且任意...

微服務專題學習01

springboot結合前端有很多種方法,比如在static裡面直接加入css或js,又或者引入webjars,以jar包的形式加入專案 webjars形式 pom 檔案 引用bootstrap org.webjars groupid bootstrap artifactid 3.3.7 1 ver...

動態規劃專題

多階段過程轉化為一系列單階段問題,利用各階段之間的關係,逐個求解,創立了解決這類過程優化問題的新方法 動態規劃 個人的理解 就是處於當前決策時要依賴前面的已知情況,將看似 連續無統一標準解決方案 的問題分割成多個 可以商量的 的決策過程。商量就是依靠已知的情況覺得未知 那麼什麼問題才可以用到動態規劃...