国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

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

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

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

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

掃碼添加小助手

加入工程師交流群

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

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

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

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

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

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

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

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

排列問題的兩種視角

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

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)是如何推導出來的?為了搞清楚這個問題,我需要講一點組合數(shù)學的知識。

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

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

即,將n個標記了不同序號的球(標號為了體現(xiàn)順序的差異),放入k個標記了不同序號的盒子中(其中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個盒子。

結合上述兩種情況,可以得到:

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

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

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

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

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

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

例題分析

看一下力扣第 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ī)模更小的子問題,然后通過子問題的答案推導出原問題的答案。

首先,我們可以這樣定義一個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ù),題目想要的結果是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)轉移方程進行窮舉。

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

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

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

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

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

--定義: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)){
//累加結果
res+=dp(s,k+1,t,j+1);
}
}
returnres;
}

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

//備忘錄
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)轉移方程
//在s[i..]中尋找k,使得s[k]==t[j]
for(intk=i;kif(s.charAt(k)==t.charAt(j)){
//累加結果
res+=dp(s,k+1,t,j+1);
}
}
//存入備忘錄
memo[i][j]=res;
returnres;
}

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

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

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

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

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

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

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

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

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

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

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

//定義:s[i..]的子序列中 t[j..]出現(xiàn)的次數(shù)為 dp(s, i, t, j)
intdp(Strings,inti,Stringt,intj){
if(s[i]==t[j]){
//匹配,兩種情況,累加關系
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)轉移方程
if(s.charAt(i)==t.charAt(j)){
//匹配,兩種情況,累加關系
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);
}
//結果存入備忘錄
memo[i][j]=res;
returnres;
}

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

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

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

--- EOF ---

審核編輯 :李倩


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

    關注

    3

    文章

    4417

    瀏覽量

    67514
  • 數(shù)組
    +關注

    關注

    1

    文章

    420

    瀏覽量

    27360

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

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數(shù)據(jù)結構】歡迎添加關注!文章轉載請注明出處。

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    TVS vs TSS 兩種保護機制的深度博弈

    在現(xiàn)代電子設備日益精密、工作環(huán)境愈發(fā)復雜的背景下,電路安全問題尤其是雷擊和瞬態(tài)過壓(Surge)防護,已成為產(chǎn)品設計中不可忽視的重要環(huán)節(jié)。其中,TVS(瞬態(tài)電壓抑制器)與TSS(晶閘管浪涌抑制器)是兩種廣泛應用的浪涌保護器件。盡管二者均服務于同一目標——保障電路
    的頭像 發(fā)表于 02-12 15:23 ?706次閱讀
    TVS vs TSS <b class='flag-5'>兩種</b>保護機制的深度博弈

    使用Firebase AI Logic生成圖像模型的兩種新功能

    為您的應用添加自定義圖像,能夠顯著改善和個性化用戶體驗,有效提高用戶參與度。本文將探討使用 Firebase AI Logic 生成圖像的兩種新功能: 其一是 Imagen 專屬編輯功能預覽版;其二
    的頭像 發(fā)表于 11-30 09:28 ?429次閱讀

    兩種電流檢測電路設計方案 高側 低側 最高耐壓90V

    常用的電流檢測電路有兩種,一是低壓側電流檢測,另一是高壓側電流檢測。 實現(xiàn)方法: 兩種電流檢測電路工作原理一致,都是將采集到的電流以電壓的形式呈現(xiàn),對電壓信號進行放大,送入ADC處
    的頭像 發(fā)表于 11-24 16:16 ?1165次閱讀
    <b class='flag-5'>兩種</b>電流檢測電路設計方案 高側 低側 最高耐壓90V

    用PLC實現(xiàn)卷徑計算的兩種算法

    卷徑計算,是動態(tài)計算如鋼卷,紙卷等存料量的一方法,它是實現(xiàn)張力控制和自動充放料、以及甩尾控制的重要前提。卷徑計算目前主流的方法有兩種,一是根據(jù)機列速度(產(chǎn)線速度)和和被測卷的轉動角
    的頭像 發(fā)表于 11-14 16:54 ?2083次閱讀
    用PLC實現(xiàn)卷徑計算的<b class='flag-5'>兩種</b>算法

    基于SIMP與折衷規(guī)劃法的航空附件齒輪箱結構輕量化設計與動態(tài)特性提升

    航空發(fā)動機附件齒輪箱作為動力傳遞系統(tǒng)的關鍵部件,其箱體結構設計直接影響發(fā)動機的功率密度、可靠性及振動特性。針對傳統(tǒng)經(jīng)驗設計方法難以滿足高剛度、輕量化及高動態(tài)性能要求的挑戰(zhàn),本文提出了一基于折衷規(guī)劃法的多目標拓撲優(yōu)化方法。
    的頭像 發(fā)表于 11-07 15:21 ?744次閱讀
    基于SIMP與折衷<b class='flag-5'>規(guī)劃</b>法的航空附件齒輪箱結構輕量化設計與<b class='flag-5'>動態(tài)</b>特性提升

    ADI GMSL技術兩種視頻數(shù)據(jù)傳輸模式的區(qū)別

    本文深入介紹GMSL技術,重點說明用于視頻數(shù)據(jù)傳輸?shù)南袼啬J胶退淼滥J街g的差異。文章將闡明這兩種模式之間的主要區(qū)別,并探討成功實施需要注意的具體事項。
    的頭像 發(fā)表于 10-10 13:49 ?2320次閱讀
    ADI GMSL技術<b class='flag-5'>兩種</b>視頻數(shù)據(jù)傳輸模式的區(qū)別

    兩種TVS有啥不同?

    當我們查看TVS二極管的規(guī)格書,常會看到有以下兩種種引腳功能標識圖:對于初學者,看到感到疑惑,他們一樣嗎?他們有啥區(qū)別?為啥有的個尖頭往外,陽極連在一起,有的個尖頭往里,陰極連在一起?一連三問。EMC小哥根據(jù)自己經(jīng)驗略作分析
    的頭像 發(fā)表于 09-15 20:27 ?800次閱讀
    這<b class='flag-5'>兩種</b>TVS有啥不同?

    兩種散熱路徑的工藝與應用解析

    背景:兩種常見的散熱設計思路 在大電流或高功率器件應用中,散熱和載流能力是PCB設計中必須解決的難題。常見的兩種思路分別是: 厚銅板方案:通過整體增加銅箔厚度(如3oz、6oz甚至更高),增強導熱
    的頭像 發(fā)表于 09-15 14:50 ?787次閱讀

    CMOS 2.0與Chiplet兩種創(chuàng)新技術的區(qū)別

    摩爾定律正在減速。過去我們靠不斷縮小晶體管尺寸提升芯片性能,但如今物理極限越來越近。在這樣的背景下,兩種創(chuàng)新技術站上舞臺:CMOS 2.0 和 Chiplet(芯粒)。它們都在解決 “如何讓芯片更強” 的問題,但思路卻大相徑庭。
    的頭像 發(fā)表于 09-09 15:42 ?1028次閱讀

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

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

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

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

    兩種驅動方式下永磁直線開關磁鏈電機的研究

    摘要:永磁開關磁鏈電機數(shù)學模型可以等效為永磁無刷電機,普遍采用方波驅動方式。在有限元基礎上分析6/7極直線式磁鏈電機反電勢波形,采用方波和正弦波驅動方式,比較兩種方式下的電流、電壓、平均推力大小
    發(fā)表于 06-09 16:18

    兩種感應電機磁鏈觀測器的參數(shù)敏感性研究

    模式和發(fā)電模式下對閉環(huán)電壓電流模型磁鏈觀測器和滑模磁鏈觀測器參數(shù)敏感性進行了研究,通過仿真和實驗比較了這兩種觀測器對定、轉子電阻及勵磁電感的敏感性。同時還研究了基于這兩種觀測器的模型參考自適應系統(tǒng)
    發(fā)表于 06-09 16:16

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

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

    銣原子鐘與CPT原子鐘:兩種時間標準的區(qū)別

    在物理學的世界中,精密的時間測量是至關重要的。這就需要一個高度準確且穩(wěn)定的時間標準,這就是原子鐘。今天我們將探討兩種重要的原子鐘:銣原子鐘和CPT原子鐘,以及它們之間的主要區(qū)別。首先,我們來了解一下
    的頭像 發(fā)表于 05-22 15:49 ?737次閱讀
    銣原子鐘與CPT原子鐘:<b class='flag-5'>兩種</b>時間標準的區(qū)別