分治法「戳氣球」

2021-10-04 10:15:26 字數 1722 閱讀 2153

最後的解法多半是貪心或者動態規劃,大概率動態規劃。

但依照流程來看,找不到最優子結構。每次戳氣球都會影響之後戳的氣球,狀態太多了。

比如同樣是戳數字5號,因為之前戳氣球的情況不同,左右鄰居不同,這意味著戳5號的情況不能復用。

就這樣想著,完全找不到思路。(後來發現是被正向思維給限制了)

幹想也沒辦法,直接用動態規劃的正規化硬做。

nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] -->

想一下遞迴式,比如現在只剩1號,戳1號後,最後答案為 戳完前面的3號+戳完後面5,8號+戳1號,因為是最後戳1號,所以戳1號的值為 start1號end,戳前面和後面遞迴呼叫即可。一下就有思路了。原來得逆向戳氣球,假設最後一次戳氣球是x,這時因為只剩x沒有鄰居可以直接算出值為x,前面和後面的空缺再遞迴呼叫戳氣球就可以了!

對於此題我們需要反過來思考,因為正向思考的話情況過於複雜,而且狀態轉換方程根本沒法寫,所以不妨試著逆向思考,也就是動態規劃的「自底向上」的思考方式,我先思考最簡單的情況,在來推出稍微複雜的情況。

其實反思過來動態規劃本身就是逆向的思維,從最後一步往前推。先假設最後乙個生育的氣球是k,那麼由此我們可以將問題分為dp(i,k)和dp(k,j)兩部分從而達到分而治之的目的。其實在分支的過程中也用到了動態規劃的思想,即用for迴圈來保證k是能取到陣列裡的每一位數,即每乙個氣球都是可能最後乙個被戳到,然後再從這裡面尋找最大值,不過要注意的是,由於邊界不能被選中,我們需要向將原陣列擴容,即nums[-1]=nums[end+1]=1;然後再傳入函式,這是遞迴結束的條件時只剩下兩邊的「1」,

class

solution

intdp

(vector<

int>

&nums,

int i,

int j,vector

int>>

&memo)

memo[i]

[j]=max;

return max;}}

;

1.3 迭代-動態規劃(繼續1.2,自底而上思考)

可將1.2中的快取表作為dp表,填表即可。通過從最小子問題開始進行簡單嘗試,可以發現長度為2的子問題的解僅依賴於長度為1子問題的解;長度為3的子問題的解僅依賴於長度為2的子問題的解

注意此處我們的填表順序是斜著來的,這是因為我們的i和j分別是乙個區間的開始可結束標誌,又由我們的分析可知,我們劃分的標準是「區間長度」,即我們要先求出所有區間長度為i的dp,才能以此選出最大的值來繼續求區間長度為「i+1」的dp值,所以是 fill(dp,nums,j,j+i);

dp[i][j]的含義是,區間i~j上能取得的最大收益,最終的最大收益當然是

dp[0][nums.length-1].

class

solution

for(

int i =

0; i

return dp[0]

[nums.length-1]

;}void

fill

(int

dp,int nums,

int start,

int end)

dp[start]

[end]

= max;

}}

312 戳氣球 使用回溯,分治,dp

可以使用三種方法 回溯法,回溯法可以遍歷每一種可能,屬於暴力解法。分治法,分治法首先要得到狀態轉移方程。dp動態規劃 首先為陣列增加首位 fun i,j 相當於不戳邊界 i,j。戳其中的任意乙個氣球得到的硬幣數。對於確定的最後戳中間k索引的氣球fun i,j fun i,k fun k,j nums...

騰訊面試 戳氣球

有 n 個氣球,編號為0 到 n 1,每個氣球上都標有乙個數字,這些數字存在陣列 nums 中。現在要求你戳破所有的氣球。每當你戳破乙個氣球 i 時,你可以獲得 nums left nums i nums right 個硬幣。這裡的 left 和 right 代表和 i 相鄰的兩個氣球的序號。注意當...

312 戳氣球 動態規劃

難度 困難 2020 7 19每日一題打卡 題目描述 解題思路 今天是抄答案而且還抄的迷迷糊糊的一天 知道要這樣做,但是仔細去想為什麼是這樣的,又說不出個所以然 首先在陣列左右兩端新增虛擬氣球節點,是不能被戳破的,這樣能方便處理邊界,而且保證總是有三個氣球相乘。然後注意動態規劃的順序,要從區間右邊開...