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

Analysis

A very nice analysis on LeetCode talking about several approaches from brute-force to divide and conquer as well as dynamic programming:

https://leetcode.com/problems/burst-balloons/discuss/76228/Share-some-analysis-and-explanations

一、利用分治法Divide and Conquer结合记忆化memoization

二、或者利用区间型动态规划Dynamic Programming

Divide and Conquer with Memoization

https://mnmunknown.gitbooks.io/algorithm-notes/625,_dong_tai_gui_hua_ff0c_qu_jian_lei_dp.html

https://leetcode.com/problems/burst-balloons/discuss/76245/Easiest-Java-Solution

subproblems are overlapped, so we can use divide and conquer + cache

  • Balloons 0, 1, ..., n - 1

  • What is the max value if we burst all of them[0, n - 1]?

  • Let's first consider bursting[start, end] (including start and end boundaries)

  • Imagine index i as the last one in the interval to be bursted

  • [start, ... i - 1, (i), i + 1 ... end]

  • Before the end, we already bursted [start, i - 1] and [i + 1, end]

  • Before the end, boundaries start - 1 , i , end + 1 are always there

  • This helps us calculate coins without worrying about details inside[start, i - 1] and [i + 1, end]

  • So the range can be divided into start - 1 ,maxCoin(start, i - 1), i, maxCoins(i + 1, end), end + 1

基本思想就是在区间[start, end]中循环ii作为该区间内最后被爆的气球,这样区间被分成了左右两个区间,再依次递归地寻找 [start, i - 1][i + 1, end] 的区间。这样就变成了子问题,而子问题区间上是可能有重叠的,因此可以用memoization来优化递归。

Dynamic Programming

这题的难点在于,如何在动态变化的数组中,正确定义并计算subproblem.

因为数组一直在变化,如何计算每次打爆获得的coin呢?

是否可以将子问题定义为寻找(left, right)区间内能得到最多的coin数目? 难想到的是从最后被打爆的气球入手,这种情况下,区间的左右两个两个元素就是确定的,而改变(循环i)区间内最后被打爆的气球则会得到不同的结果,从而找到最大

State:

  • dp[i][j]表示 i 到 j 区间中,打爆所有气球的最大coin数目

Function:

  • 对于所有k属于{i,j}, 表示第k号气球最后打爆。k is the last balloon to burst.

    • midValue = arr[i- 1] * arr[k] * arr[j + 1];

    • dp[i][j] = max(dp[i][k-1] + d[k+1][j] + midvalue)

Initialize:

  • for each i

    • dp[i][i] = 0

Answer:

  • dp[0][n-1]

Solution

Divide & Conquer + Recursive + Memoization - Easy to Understand Solution (16 ms, faster than 14.04%)

https://leetcode.com/problems/burst-balloons/discuss/76245/Easiest-Java-Solution

start, end boundary included (boundaries will be burst)

[start, ... i - 1, (i), i + 1 ... end]

*(Favorite) - Same idea as above (Divide & Conquer with Memoization) but faster performance (6ms 87.86%)

Building a new array first for faster access, compared to above getVal() function

Other answers for reference

*Divide and Conquer, Memoization, Recursive - (Runtime: 5 ms, faster than 99.18%)

(not including boundaries in the recursion - boundary balloons not bursted)

Dynamic Programming - 6 ms , faster than 88.28%

Reference

Last updated

Was this helpful?