312 - Burst Balloons

題目介紹

Given?n?balloons, indexed from?0?to?n-1. Each balloon is painted with a number on it represented by array?nums. You are asked to burst all the balloons. If the you burst balloon?i?you will get?nums[left] * nums[i] * nums[right]?coins. Here?left?and?right?are adjacent indices of?i. After the burst, the?left?and?right?then becomes adjacent.

Find the maximum coins you can collect by bursting the balloons wisely.

Note:

You may imagine?nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.

0 ≤?n?≤ 500, 0 ≤?nums[i]?≤ 100

Example:

Input:[3,1,5,8]Output:167Explanation: nums = [3,1,5,8] --> [3,5,8] -->? [3,8]? -->? [8]? --> []?? ? ? ? ? ? coins =? 3*1*5? ? ? +? 3*5*8? ? +? 1*3*8? ? ? + 1*8*1? = 167


翻譯

有?n?個氣球,編號為0?到?n-1,每個氣球上都標有一個數字,這些數字存在數組nums中。

現在要求你戳破所有的氣球。每當你戳破一個氣球?i?時,你可以獲得nums[left] * nums[i] * nums[right]個硬幣。?這里的left和right代表和i相鄰的兩個氣球的序號。注意當你戳破了氣球?i?后,氣球left和氣球right就變成了相鄰的氣球。

求所能獲得硬幣的最大數量。

說明:

你可以假設nums[-1] = nums[n] = 1,但注意它們不是真實存在的所以并不能被戳破。

0 ≤?n?≤ 500, 0 ≤?nums[i]?≤ 100


解題思路

? ? ????首先,第一個思路是暴力求解,枚舉出所有可能的排列可能,然后算分數,并取最大值。但是,顯然,我們會有n!中可能的排列,時間復雜度太大,因而放棄它。

? ? ????之后,我在想,能否將原問題分解成子問題,遞歸求解。以【3,1,5,8】為例,因為,踩氣球是一個一個地踩,我可以做的一個行為是任踩一個氣球,計算目前所得分數,并加上剩余氣球能夠得到的分數,由于,我有多種選擇的可能性,那么,我就計算所有的可能,并選取得分最高的方案。如,【3,1,5,8】 可有四種方案,3*1 + 【1,5,8】,3*1*5 +【3,5,8】,1*5*8 +【3,1,8】和 5*8 + 【3,1,5】。倘若遞歸的數列長度等于3,那么,我們就枚舉出3!= 6種可能性,然后選擇最大的分數返回。同時每當計算出一組序列的得分時,就把它存在一個字典dic里, 如dic[(5,8)] = 48,當需要求的序列的分數已經存在與dic中式,直接將其求出。但是,這種遞歸的時間復雜度也很高。之后,我在想,現在復雜度高的原因,是對于每一個長度為m的序列,我都要枚舉出m種可能,那么迭代后復雜度必然高,那么,會不會存在一種規律使得我可以不每次都枚舉m種可能,而是,最有結果出現在有限的幾種可能中呢?于是,我做出了幾個猜想,1. 每次先踩分數最小的(失敗,反例【1,2,100,1】)2. 每次先踩其相鄰兩個數之積最大的數(失敗,反例【9,76,64,21,97,60,5】)。

????? ? 由于沒有找到一種可以降低枚舉可能次數的策略,所以,我將思路放在DP上,因為,有一個很明顯的直覺,就是倘若知道任意一個子段可以取得的最大分數,那么,我就可以求得整個子段的最大分數。既然決定了使用DP,那么之后我就開始著手重新定義原問題。

? ????? 首先,我思考,能否將一個長度為n的數列 l 看成是為 l[0:-1] 和 l[-1],兩部分,那么,倘若我知道了前一部分的最大分數,那么我只需要再讓它加上踩破最后一個的分數,如【3,1,5,8】可分為【3,1,5】和【8】,那么最大的分數是score(【3,1,5】)+ 8*5,然后從0到n-1依次遞歸。但這樣顯然書錯誤的,因為,這樣定義問題實際上是附加了一個隱含條件,即,一定要先踩最后一個氣球,再踩前面的氣球,這顯然與原問題不符。

????? ? 雖然,上面的假設是錯誤的,但是,卻給了我一個思路,如何將上面假設做適當修改,使他符合原題呢?經過思考,我覺得,問題的關鍵在于 -- 每次踩的氣球都是隨機的。既然每次踩的氣球的是隨機的,那么,我就先假設踩的氣球是第m個(假設數列為nums,長度為L,m<L)。在我踩了第m個氣球后,造成的結果是什么?那就是,原數列變成了兩部分,nums[:m]和num[m+1:L-1],同時,由于這一腳,我獲得了nums[m-1]*nums[m]*nums[m+1]分

? ? ????原本以后我將問題這樣轉化后在DP就可以通過了,然而結果卻顯示了錯誤。我又進行了分析,結果發現了一個問題,倘若我踩了第k個氣球,那么當踩第k-1個氣球時,會發生什么情況呢?會發生計算它的分數時,它的右側是沒有球的!!這顯然不合理,因為踩了第k個氣球后,它后面會接在第k-1個氣球后。 那么,我想著能不能把第在計算第k-1個氣球得分時,將它的右側氣球強制定義為第k+1個氣球。粗想一下感覺可行,但是,仔細一想就發現了問題,倘若第k+1氣球在第k-1個氣球之前被踩爆了,怎么辦? 這個問題會越來越復雜,最重要的是被分割成兩半的nums[:m]和num[m+1:L-1]和變得彼此不獨立,而這對DP來說是難以接受的。

? ? ????緊接著,我的問題就變成了,如何使被切分的兩部分變得彼此獨立。經過思考,我發現,這兩部分的獨立與否,取決與nums[k-1]的右側氣球是誰和nums[k+1]的左側氣球是誰。當第k個氣球被踩爆了,那么nums[k-1]的右側氣球和nums[k+1]的左側氣球就會發生變化.....(ーー゛),那我不睬第k個氣球了!!!那么,我就可以保證nums[k-1]的右側氣球和nums[k+1]的左側氣球都不會變化,因為都是第k個氣球,然而,我不可能不猜它呀!!!思考后,我意識到,我只要在nums[:m]和num[m+1:L-1]都被踩爆后再踩第k個氣球,那么就可以達到我隔離兩邊的目的了。

????????現在,還剩一步,就是計算踩爆第k個氣球的得分,當k是原問題最后一個被踩爆的氣球時,可增加分數nums[k],即它本身,然而,這個規律卻不適合與其子問題,如原問題是【1,2,3,4,5,6,7,8】,【4,5,6】是它的一個子問題,假如5所代表的氣球是子問題中最后被踩爆的,那么它的得分顯然不是5,因為她并不是全局最后一個被踩爆的,它周圍必要還有其他氣球。然而它左右的氣球會存在與其他的子問題中,并且是變化的,這是不能接受的。于是,我想著怎么把最后一個踩爆的氣球左右的氣球固定住。于是就假設序列的最左端和最右段氣球被最后踩爆,而第k個氣球是在非最左和非最右氣球外被最后踩爆的,那么第k個氣球的分數就固定了,即 最左的分數×本身的分數×最右的分數。

? ? ? ? 之后,在回顧一遍原問題的第k個氣球被最后踩爆,那么,它的得分就是最左的分數×本身的分數×最右的分數,這顯然不對,因為,這相當于隱性的規定原問題最左邊和最右邊的氣球被最后踩爆。這時候有兩種方式,一種是強行指定,在第一次從原問題處理分離子問題時,分數之加這個氣球本身的分數,其他情況則加 最左的分數×本身的分數×最右的分數。另一種方法就是在原問題分數序列左右都加上1,這樣既不影響最終分數,又避免了第一次分離子問題時出現的例外情況。? ? ? ??

? ? ? ? 至此,我們所做的只是計算出最后踩爆第k個氣球的得分,而題目要求的是踩爆氣球的最大得分,因此,我們可以遍歷所有的,并取其中得分最大的作為答案。

? ? ? ? 以上,是我做題時的思考,下面,再總結一下要點:

? ? ? ? 1. 重新定義問題:計算任意一個氣球被最后踩爆時的最大得分,并分返回其中的最大值。

? ? ? ? 2. 使用動態規劃處理這個問題,將原問題分為nums[0:k] 和 num[k:L-1]兩部分,并獲得加分 nums[0]*nums[k]*nums[1]

? ? ? ? 3. 遍歷所有的k,從中取得得分最多的方案。

? ? ? ? 4. 在原數列兩邊加邊框1,以匹配第一次分離子問題的情況。


? ? ????代碼:

????????https://github.com/guiguiJY/Leetcode/blob/master/312.py

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Description Given n balloons, indexed from 0 to n-1. Each...
    Nancyberry閱讀 290評論 0 0
  • (DP動態規劃) Leetcode 312. Burst Balloons 第一次做動態規劃的題目 題目 Give...
    jeff98閱讀 235評論 0 0
  • Given n balloons, indexed from 0 to n-1. Each balloon is ...
    Jeanz閱讀 279評論 0 0
  • 《音速小子》里的索尼克一直是速度的化身,小時候我們玩著這款家喻戶曉的游戲式總是希望著能夠跟索尼克一樣擁有別人無...
    瑣碎布丁閱讀 181評論 0 0
  • 歲月走的悄然無聲 留下多少人孑然一身 是否還可以相信 會出現那個一起守候時光的人
    卿莫遲閱讀 149評論 0 0