[LeetCode](week12)312. Burst Balloons

(DP動態規劃) Leetcode 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: 167 
Explanation: 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

題目解析與分析

題意

大概就是:有一排氣球,每個標了數字,然后戳一個氣球得到的獎勵是左氣球×該氣球×右氣球,當然如果左或右沒有氣球就乘1。問該以什么順序戳氣球得到的獎勵最大

最笨的思路

枚舉法:將所有的情況列舉一遍。當有n個氣球的時候,第一步我們有n種選擇,第二步我們又有n-1個選擇......顯然全枚舉的算法復雜度為O(N!),效率不敢恭維,因此這里就不實現——因為不可能過。

參閱

進一步想法

我們需要去考慮上面枚舉法做了什么重復的計算。我們可以想到,給定一組氣球,它所能獲得的最大的獎勵應該和前面已經被戳的氣球無關——被戳過的氣球只是在求和的時候累積上了而已。

對于給定k<n, 其可能的組合數有 C_n^k 種,我們可以把k(從1開始)的所有情況都記錄在內存上,k+1就可以基于k進行計算,那么我們總共需要進行的計算就是
C_n^1+C_n^2+...+C_n^n
這種算法優于O(N!), 但仍然壞于O(2^N); 我們需要更優的算法

分治的想法

我們考慮用分治去思考這一道題。先是正常地考慮分治,我戳爆某個氣球,可不可以把剩下的氣球分成兩堆呢?這是否可行的前提是兩堆會不會互相干擾:答案是肯定的,在戳爆某個氣球以后,左堆的最右氣球會需要右堆的最左氣球來進行計算。

這時候我們需要反向的思維:我們正向地想戳氣球的過程,當然會導致兩堆相互影響。那如果我們考慮的是在這一堆里最后戳爆的那個氣球呢?假如A,B,C,D,E中我最后戳C, 那左堆(A,B)在戳的過程中顯然會以C為右邊界,而右堆(D,E)以C為左邊界——這就實現了分治,兩個子問題是相互不干擾的。

想一下為什么分治會更好,它少算了哪些步驟

具體的算法如下:

public int maxCoins(int[] iNums) {
    int[] nums = new int[iNums.length + 2];
    int n = 1;
    for (int x : iNums) if (x > 0) nums[n++] = x;
    nums[0] = nums[n++] = 1;


    int[][] memo = new int[n][n];
    return burst(memo, nums, 0, n - 1);
}

public int burst(int[][] memo, int[] nums, int left, int right) {
    if (left + 1 == right) return 0;
    if (memo[left][right] > 0) return memo[left][right];
    int ans = 0;
    for (int i = left + 1; i < right; ++i)
        ans = Math.max(ans, nums[left] * nums[i] * nums[right] 
        + burst(memo, nums, left, i) + burst(memo, nums, i, right));
    memo[left][right] = ans;
    return ans;
}
// 12 ms
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Description Given n balloons, indexed from 0 to n-1. Each...
    Nancyberry閱讀 290評論 0 0
  • 今天爵士隊主場以116比69狂剁來訪的奇才隊,凈勝47分是爵士隊本賽季新高,69分也創造了本賽季得分新低。此役過后...
    掌趣體育閱讀 280評論 0 0
  • 人真的很多,一會不看就會有很多信息。正在想著一種方法,可以有效的吸收所有知識。 但我發現,大部分人,雖然有在學習,...
    把快樂帶給你閱讀 158評論 0 0
  • 冬天來了,住在我自己租的小房子里半夜都被凍醒了,洗澡的水已經不夠用了,沒太在意居然洗著洗著就沒熱水了,這個冬天還沒...
    幸運星新閱讀 206評論 0 0
  • “菜根”一詞出自北宋學者汪信民的一句“咬得菜根,百事可做”,意思是一個人只要能適應清貧艱苦的生活,以后無論做什么事...
    MuSky_沐卿心閱讀 5,498評論 0 34