女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

論動態(tài)規(guī)劃窮舉的兩種視角

算法與數(shù)據(jù)結(jié)構(gòu) ? 來源:labuladong ? 作者:labuladong ? 2022-07-11 14:49 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

挺久沒寫動態(tài)規(guī)劃相關(guān)的題目了,本文我?guī)Т蠹覐?fù)習(xí)一下動態(tài)規(guī)劃相關(guān)問題的一系列解題套路,然后著重討論一下動態(tài)規(guī)劃窮舉時不同視角的問題。

動態(tài)規(guī)劃解題組合拳

首先,前文我的刷題心得講了,我們刷的算法問題的本質(zhì)是「窮舉」,動態(tài)規(guī)劃問題也不例外,你必須想辦法窮舉所有可能的解,然后從中篩選出符合題目要求的解。

另外,動態(tài)規(guī)劃問題窮舉的過程中會出現(xiàn)重疊子問題導(dǎo)致的冗余計算,所以前文動態(tài)規(guī)劃核心套路框架中告訴你如何一步一步把暴力窮舉解法優(yōu)化成效率更高的動態(tài)規(guī)劃解法。

然而,想要寫出暴力解需要依據(jù)狀態(tài)轉(zhuǎn)移方程,狀態(tài)轉(zhuǎn)移方程是動態(tài)規(guī)劃的解題核心,可不是那么容易想出來的。不過,前文動態(tài)規(guī)劃設(shè)計:數(shù)學(xué)歸納法告訴你,思考狀態(tài)轉(zhuǎn)移方程的一個基本方法是數(shù)學(xué)歸納法,即明確dp函數(shù)或數(shù)組的定義,然后使用這個定義,從已知的「狀態(tài)」中推導(dǎo)出未知的「狀態(tài)」。

還沒完,比如高樓扔雞蛋問題中對dp函數(shù)/數(shù)組的定義不見得是唯一的,不同的定義會導(dǎo)致狀態(tài)轉(zhuǎn)移方程發(fā)生變化,解題效率也有高低之分,所以我們應(yīng)該給dp函數(shù)盡可能想出更合適的定義來解題。

接下來就是本文要著重探討的問題了:就算dp函數(shù)/數(shù)組的定義相同,如果你使用不同的「視角」進行窮舉,效率也不見得是相同的

關(guān)于窮舉「視角」的問題,前文回溯算法窮舉視角:子集劃分問題講了回溯算法中不同的窮舉視角導(dǎo)致的不同解法,其實這種視角的切換在動態(tài)規(guī)劃類型問題中依然存在。前文對排列的舉例非常有助于你理解窮舉視角的問題,這里再簡單提一下。

排列問題的兩種視角

我們先回顧一下以前學(xué)過的排列組合知識:

1、P(n, k)(也有很多書寫成A(n, k))表示從n個不同元素中拿出k個元素的排列(Permutation/Arrangement);C(n, k)表示從n個不同元素中拿出k個元素的組合(Combination)總數(shù)。

2、「排列」和「組合」的主要區(qū)別在于是否考慮順序的差異。

3、排列和組合總數(shù)的計算公式如下:

56b5fdd6-00e4-11ed-ba43-dac502259ad0.png

好,現(xiàn)在我問一個問題,這個排列公式P(n, k)是如何推導(dǎo)出來的?為了搞清楚這個問題,我需要講一點組合數(shù)學(xué)的知識。

排列組合問題的各種變體都可以抽象成「球盒模型」,P(n, k)就可以抽象成下面這個場景:

56d49020-00e4-11ed-ba43-dac502259ad0.jpg

即,將n個標(biāo)記了不同序號的球(標(biāo)號為了體現(xiàn)順序的差異),放入k個標(biāo)記了不同序號的盒子中(其中n >= k,每個盒子最終都裝有恰好一個球),共有P(n, k)種不同的方法。

現(xiàn)在你來,往盒子里放球,你怎么放?其實有兩種視角。

首先,你可以站在盒子的視角,每個盒子必然要選擇一個球。

這樣,第一個盒子可以選擇n個球中的任意一個,然后你需要讓剩下k - 1個盒子在n - 1個球中選擇:

56eaff90-00e4-11ed-ba43-dac502259ad0.jpg

另外,你也可以站在球的視角,因為并不是每個球都會被裝進盒子,所以球的視角分兩種情況:

1、第一個球可以不裝進任何一個盒子,這樣的話你就需要將剩下n - 1個球放入k個盒子。

2、第一個球可以裝進k個盒子中的任意一個,這樣的話你就需要將剩下n - 1個球放入k - 1個盒子。

結(jié)合上述兩種情況,可以得到:

57055a98-00e4-11ed-ba43-dac502259ad0.jpg

你看,兩種視角得到兩個不同的遞歸式,但這兩個遞歸式解開的結(jié)果都是我們熟知的階乘形式:

57182146-00e4-11ed-ba43-dac502259ad0.png

至于如何解遞歸式,涉及數(shù)學(xué)的內(nèi)容比較多,這里就不做深入探討了,有興趣的讀者可以自行學(xué)習(xí)組合數(shù)學(xué)相關(guān)知識。

當(dāng)然,以上只是純數(shù)學(xué)的推導(dǎo),P(n, k)的計算結(jié)果也僅僅是一個數(shù)字,所以以上兩種窮舉視角從數(shù)學(xué)上講沒什么差異。但從編程的角度來看,如果讓你計算出來所有排列結(jié)果,那么兩種窮舉思路的代碼實現(xiàn)可能會產(chǎn)生性能上的差異,因為有的窮舉思路難免會使用額外的 for 循環(huán)拖慢效率,這也是前文回溯算法窮舉視角:子集劃分問題主要探討的。

本文不講回溯算法和排列組合,不過請你記住這個例子,待會會把這種窮舉視角的差異運用到動態(tài)規(guī)劃題目當(dāng)中。

例題分析

看一下力扣第 115 題「不同的子序列」:給你輸入一個字符串s和一個字符串t,請你計算在s的子序列中t出現(xiàn)的次數(shù)。比如題目給的例子,輸入s = "babgbag", t = "bag",算法返回 5:

57242356-00e4-11ed-ba43-dac502259ad0.jpg

函數(shù)簽名如下:

intnumDistinct(Strings,Stringt);

你要數(shù)一數(shù)s的子序列中有多少個t,說白了就是窮舉嘛,那么首先想到的就是能不能把原問題分解成規(guī)模更小的子問題,然后通過子問題的答案推導(dǎo)出原問題的答案。

首先,我們可以這樣定義一個dp函數(shù):

//定義:s[i..]的子序列中 t[j..]出現(xiàn)的次數(shù)為 dp(s, i, t, j)
intdp(Strings,inti,Stringt,intj)

這道題對dp函數(shù)的定義很簡單直接,題目讓你求出現(xiàn)次數(shù),那你就定義函數(shù)返回值為出現(xiàn)次數(shù)就可以。

有了這個dp函數(shù),題目想要的結(jié)果是dp(s, 0, t, 0),base case 也很容易寫出來,解法框架如下:

intnumDistinct(Strings,Stringt){
returndp(s,0,t,0);
}

//定義:s[i..]的子序列中 t[j..]出現(xiàn)的次數(shù)為 dp(s, i, t, j)
intdp(Strings,inti,Stringt,intj){
//basecase1
if(j==t.length()){
//t已經(jīng)全部匹配完成
return1;
}
//basecase2
if(s.length()-i// s[i..]比 t[j..]還短,必然沒有匹配的子序列
return0;
}

//...
}

好,接下來開始思考如何利用這個dp函數(shù)將大問題分解成小問題,即如何寫出狀態(tài)轉(zhuǎn)移方程進行窮舉。

回顧一下之前講的排列組合的「球盒模型」,這里是不是很類似?t中的若干字符就好像若干盒子,s中的若干字符就好像若干小球,你需要做的就是給所有盒子都裝一個小球。

所以這里就有兩種窮舉思路了,分別是站在t的視角(盒子選擇小球)和站在s的視角(小球選擇盒子)。

視角一,站在t的角度進行窮舉

我們的原問題是求s[0..]的所有子序列中t[0..]出現(xiàn)的次數(shù),那么可以先看t[0]s中的什么位置,假設(shè)s[2], s[6]是字符t[0],那么原問題轉(zhuǎn)化成了在s[2..]s[6..]的所有子序列中計算t[1..]出現(xiàn)的次數(shù)。

寫成比較偏數(shù)學(xué)的形式就是狀態(tài)轉(zhuǎn)移方程:

--定義:s[i..]的子序列中 t[j..]出現(xiàn)的次數(shù)為 dp(s, i, t, j)
dp(s,i,t,j)=SUM(dp(s,k+1,t,j+1)wherek>=iands[k]==t[j])

翻譯成代碼大致就是這個思路:

//定義:s[i..]的子序列中 t[j..]出現(xiàn)的次數(shù)為 dp(s, i, t, j)
intdp(Strings,inti,Stringt,intj){
intres=0;
//在s[i..]中尋找k,使得s[k]==t[j]
for(intk=i;kif(s.charAt(k)==t.charAt(j)){
//累加結(jié)果
res+=dp(s,k+1,t,j+1);
}
}
returnres;
}

這個思路應(yīng)該不難理解吧,當(dāng)然還可以加上備忘錄消除重疊子問題,最終解法如下:

//備忘錄
int[][]memo;

intnumDistinct(Strings,Stringt){
//初始化備忘錄為特殊值-1
memo=newint[s.length()][t.length()];
for(int[]row:memo){
Arrays.fill(row,-1);
}
returndp(s,0,t,0);
}

//定義:s[i..]的子序列中 t[j..]出現(xiàn)的次數(shù)為 dp(s, i, t, j)
intdp(Strings,inti,Stringt,intj){
//basecase1
if(j==t.length()){
return1;
}
//basecase2
if(s.length()-ireturn0;
}
//查備忘錄防止冗余計算
if(memo[i][j]!=-1){
returnmemo[i][j];
}
intres=0;
//執(zhí)行狀態(tài)轉(zhuǎn)移方程
//在s[i..]中尋找k,使得s[k]==t[j]
for(intk=i;kif(s.charAt(k)==t.charAt(j)){
//累加結(jié)果
res+=dp(s,k+1,t,j+1);
}
}
//存入備忘錄
memo[i][j]=res;
returnres;
}

這道題就解決了,不過效率不算很高,我們可以粗略估算一下這個算法的時間復(fù)雜度上界,其中M, N分別代表s, t的長度,算法的「狀態(tài)」就是dp函數(shù)參數(shù)i, j的組合:

帶備忘錄的動態(tài)規(guī)劃算法的時間復(fù)雜度
=子問題的個數(shù)x函數(shù)本身的時間復(fù)雜度
=「狀態(tài)」的個數(shù)x函數(shù)本身的時間復(fù)雜度
=O(MN)*O(M)
=O(N*M^2)

當(dāng)然,因為 for 循環(huán)的復(fù)雜度不總是 O(M) 且子問題個數(shù)肯定小于 O(MN),所以這是復(fù)雜度的粗略上界。不過根據(jù)前文算法時空復(fù)雜度使用指南的描述,這個上界還是說明這個算法的復(fù)雜度有些偏高。主要高在哪里呢?對「狀態(tài)」的窮舉已經(jīng)有了memo備忘錄的優(yōu)化,所以 O(MN) 的復(fù)雜度是必不可少的,關(guān)鍵問題出在dp函數(shù)中的 for 循環(huán)。

是否可以優(yōu)化掉dp函數(shù)中的 for 循環(huán)呢?可以的,這就需要另一種窮舉視角來解決這個問題。

視角二,站在s的角度進行窮舉

我們的原問題是計算s[0..]的所有子序列中t[0..]出現(xiàn)的次數(shù),可以先看看s[0]是否能匹配t[0],如果不匹配,那沒得說,原問題就可以轉(zhuǎn)化為計算s[1..]的所有子序列中t[0..]出現(xiàn)的次數(shù);

但如果s[0]可以匹配t[0],那么又有兩種情況,這兩種情況是累加的關(guān)系:

1、讓s[0]匹配t[0],那么原問題轉(zhuǎn)化為在s[1..]的所有子序列中計算t[1..]出現(xiàn)的次數(shù)。

2、不讓s[0]匹配t[0],那么原問題轉(zhuǎn)化為在s[1..]的所有子序列中計算t[0..]出現(xiàn)的次數(shù)。

為啥明明s[0]可以匹配t[0],還不讓它倆匹配呢?主要是為了給s[0]之后的元素匹配的機會,比如s = "aab", t = "ab",就有兩種匹配方式:a_b_ab

把以上思路寫成狀態(tài)轉(zhuǎn)移方程:

//定義:s[i..]的子序列中 t[j..]出現(xiàn)的次數(shù)為 dp(s, i, t, j)
intdp(Strings,inti,Stringt,intj){
if(s[i]==t[j]){
//匹配,兩種情況,累加關(guān)系
returndp(s,i+1,t,j+1)+dp(s,i+1,t,j);
}else{
//不匹配,在s[i+1..]的子序列中計算t[j..]的出現(xiàn)次數(shù)
returndp(s,i+1,t,j);
}
}

依照這個思路,再加個備忘錄消除重疊子問題,可以寫出如下解法:

int[][]memo;

intnumDistinct(Strings,Stringt){
//初始化備忘錄為特殊值-1
memo=newint[s.length()][t.length()];
for(int[]row:memo){
Arrays.fill(row,-1);
}
returndp(s,0,t,0);
}

//定義:s[i..]的子序列中 t[j..]出現(xiàn)的次數(shù)為 dp(s, i, t, j)
intdp(Strings,inti,Stringt,intj){
//basecase1
if(j==t.length()){
return1;
}
//basecase2
if(s.length()-ireturn0;
}
//查備忘錄防止冗余計算
if(memo[i][j]!=-1){
returnmemo[i][j];
}
intres=0;
//執(zhí)行狀態(tài)轉(zhuǎn)移方程
if(s.charAt(i)==t.charAt(j)){
//匹配,兩種情況,累加關(guān)系
res+=dp(s,i+1,t,j+1)+dp(s,i+1,t,j);
}else{
//不匹配,在s[i+1..]的子序列中計算t[j..]的出現(xiàn)次數(shù)
res+=dp(s,i+1,t,j);
}
//結(jié)果存入備忘錄
memo[i][j]=res;
returnres;
}

這個解法中dp函數(shù)遞歸的次數(shù),即狀態(tài)i, j的不同組合的個數(shù)為 O(MN),而dp函數(shù)本身沒有 for 循環(huán),即時間復(fù)雜度為 O(1),所以算法總的時間復(fù)雜度就是 O(MN),比剛才的解法要好一些,你提交這個解法代碼,耗時明顯比剛才的解法少一些。

至此,這道題就分析完了。我們分別站在t的視角和s的視角運用dp函數(shù)的定義進行窮舉,得出兩種完全不同但都是正確的狀態(tài)轉(zhuǎn)移邏輯,不過兩種邏輯在代碼實現(xiàn)上有效率的差異。

那么不妨進一步思考一下,什么樣的動態(tài)規(guī)劃題目可能產(chǎn)生「窮舉視角」上的差異?換句話說,什么樣的動態(tài)規(guī)劃問題能夠抽象成經(jīng)典的「球盒模型」呢?

--- EOF ---

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4380

    瀏覽量

    64845
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    420

    瀏覽量

    26539

原文標(biāo)題:論動態(tài)規(guī)劃窮舉的兩種視角

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數(shù)據(jù)結(jié)構(gòu)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    貼片晶振中兩種常見封裝介紹

    貼片晶體振蕩器作為關(guān)鍵的時鐘頻率元件,其性能直接關(guān)系到系統(tǒng)運行的穩(wěn)定性。今天,凱擎小妹帶大家聊聊貼片晶振中兩種常見封裝——金屬面封裝與陶瓷面封裝。
    的頭像 發(fā)表于 07-04 11:29 ?427次閱讀
    貼片晶振中<b class='flag-5'>兩種</b>常見封裝介紹

    AGV小車中的動態(tài)路徑規(guī)劃算法揭秘

    并非一成不變時,動態(tài)路徑規(guī)劃能力就顯得至關(guān)重要。本文將深入探討幾種主流的動態(tài)路徑規(guī)劃算法(如A、Dijkstra、RRT等),并解析它們?nèi)绾卧贏GV行業(yè)中大顯身手。 為何需要
    的頭像 發(fā)表于 06-17 15:54 ?310次閱讀
    AGV小車中的<b class='flag-5'>動態(tài)</b>路徑<b class='flag-5'>規(guī)劃</b>算法揭秘

    詳解ADC電路的靜態(tài)仿真和動態(tài)仿真

    ADC電路主要存在靜態(tài)仿真和動態(tài)仿真類仿真,針對兩種不同的仿真,我們存在不同的輸入信號和不同的數(shù)據(jù)采樣,因此靜態(tài)仿真和動態(tài)仿真是完全不同的
    的頭像 發(fā)表于 06-05 10:19 ?792次閱讀
    詳解ADC電路的靜態(tài)仿真和<b class='flag-5'>動態(tài)</b>仿真

    AMC1204有兩種封裝,SOIC-8和SOIC-16,功能一樣嗎?為什么要推出兩種封裝?

    呢?AMC1204,AMC1304這樣做有什么好處嗎? 2、AMC1204有兩種封裝,SOIC-8和SOIC-16,功能一樣嗎?為什么要推出兩種封裝?
    發(fā)表于 12-27 07:22

    ADS1292R有 \"1 ch ECG + 1 ch呼吸偵測\" 或 \"2 ch ECG\" 兩種模式,是否可以在產(chǎn)品上實現(xiàn)自行切換兩種使用模式?

    請問 ADS1292R 有 \"1 ch ECG + 1 ch 呼吸偵測\" 或 \"2 ch ECG\" 兩種模式,是否可以在產(chǎn)品上實現(xiàn)讓用戶自行切換兩種使用模式?
    發(fā)表于 12-13 14:43

    噪聲傳導(dǎo)的兩種模式

    噪聲傳導(dǎo)有兩種模式,一為差模傳導(dǎo),一為共模傳導(dǎo)。
    的頭像 發(fā)表于 10-15 11:33 ?772次閱讀
    噪聲傳導(dǎo)的<b class='flag-5'>兩種</b>模式

    Linux應(yīng)用層控制外設(shè)的兩種不同的方式

    眾所周知,linux下一切皆文件,那么應(yīng)用層如何控制硬件層,同樣是通過 文件I/O的方式來實現(xiàn)的,那么應(yīng)用層控制硬件層通常有兩種方式。
    的頭像 發(fā)表于 10-05 19:03 ?1332次閱讀
    Linux應(yīng)用層控制外設(shè)的<b class='flag-5'>兩種</b>不同的方式

    比較分析兩種不同的可提高柵極驅(qū)動電流的方法

    電子發(fā)燒友網(wǎng)站提供《比較分析兩種不同的可提高柵極驅(qū)動電流的方法.pdf》資料免費下載
    發(fā)表于 09-23 11:13 ?0次下載
    比較分析<b class='flag-5'>兩種</b>不同的可提高柵極驅(qū)動電流的方法

    紅石比較器兩種模式的作用

    紅石比較器是Minecraft中的一非常重要的紅石元件,它用于比較個紅石信號的強度,并根據(jù)比較結(jié)果輸出不同的信號強度。比較器有兩種模式:比較模式和減法模式。 比較模式 在比較模式下,比較器會將
    的頭像 發(fā)表于 09-05 09:17 ?1669次閱讀

    兩種電纜類型的特點及優(yōu)勢

    隨著技術(shù)的發(fā)展,電纜的材料和結(jié)構(gòu)不斷優(yōu)化,以滿足日益增長的電力需求和復(fù)雜的應(yīng)用環(huán)境。本文將詳細(xì)探討兩種廣泛使用的電纜類型——聚氯乙烯絕緣電纜和交聯(lián)聚乙烯絕緣電纜,它們的特點、優(yōu)勢及適用范圍。 一
    的頭像 發(fā)表于 08-28 16:23 ?1002次閱讀

    晶閘管的阻斷狀態(tài)有兩種是什么

    晶閘管(Thyristor)是一半導(dǎo)體器件,具有單向?qū)щ娦裕瑥V泛應(yīng)用于電力電子領(lǐng)域。晶閘管的阻斷狀態(tài)有兩種:正向阻斷狀態(tài)和反向阻斷狀態(tài)。以下是對這兩種阻斷狀態(tài)的分析。 正向阻斷狀態(tài) 正向阻斷狀態(tài)
    的頭像 發(fā)表于 08-14 16:49 ?1413次閱讀

    接地保護分為哪兩種方式

    接地保護是電氣工程中非常重要的一安全措施,其目的是確保電氣設(shè)備和系統(tǒng)在發(fā)生故障時能夠安全地將電流導(dǎo)向地面,從而保護人身安全和設(shè)備安全。接地保護主要分為兩種方式:工作接地和保護接地。以下是對這兩種
    的頭像 發(fā)表于 08-05 10:24 ?2309次閱讀

    plc與傳感器的兩種連接方式

    在工業(yè)自動化領(lǐng)域,PLC(可編程邏輯控制器)與傳感器的連接是實現(xiàn)自動化控制的關(guān)鍵環(huán)節(jié)。本文將詳細(xì)介紹PLC與傳感器的兩種主要連接方式:模擬量連接和數(shù)字量連接。這兩種連接方式各有優(yōu)缺點,適用于
    的頭像 發(fā)表于 07-25 09:36 ?2766次閱讀

    wdm設(shè)備的兩種傳輸方式

    系統(tǒng)中,有多種傳輸方式,其中最常見的兩種是密集波分復(fù)用(DWDM)和粗波分復(fù)用(CWDM)。 1. 密集波分復(fù)用(DWDM) 1.1 DWDM技術(shù)原理 密集波分復(fù)用(Dense Wavelength Division Multiplexing,簡稱DWDM)是一將多個不
    的頭像 發(fā)表于 07-18 09:45 ?933次閱讀

    三相負(fù)載的連接方式有哪兩種

    三相負(fù)載的連接方式主要有星形連接(Y連接)和三角形連接(Δ連接)兩種。這兩種連接方式在電氣工程中非常常見,它們各自具有不同的特性和應(yīng)用場景。下面將介紹這兩種連接方式的原理、特點、應(yīng)用以及計算方法
    的頭像 發(fā)表于 07-17 10:33 ?8063次閱讀