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:
(1) You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
(2) 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
Example:
Given [3, 1, 5, 8]
Return 167
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
Tags:Divide and Conquer,Dynamic Programming
分析:
设dp[left, right]表示扎破(left,right)范围的气球能获得的最大硬币数(但不包含边界气球),我一开始认为的状态转移方程为dp[left, right] = max(dp[left, right], dp[left, i] + nums[i-1]*nums[i]*nums[i+1] + dp[i, right]),因为题目中告诉我们在计算nums[i]对应的coins数时,是将它与它的两个邻居节点相乘,但仔细分析:dp[left, i]表示扎破(left, i)范围的气球得到的最大coins数,此时剩下的气球是left与i气球(因为dp[left, i]不含边界),同理dp[i, right]最后剩下的气球是i与right气球,即此时剩下的气球是(left,i,right),那么此时i气球获得的coin数就是nums[left]*nums[i]*nums[right]),则状态转移方程为dp[left, right] = max(dp[left, right], dp[left, i] + nums[left]*nums[i]*nums[right] + dp[i, right]),其中left<i<right,则dp[left, right] 就计算了扎破所有不包含left,right边界值的气球的coins数。
按题意应为所给数组增加值为1的首尾元素,设n为新数组的长度,那么dp[0][n-1]即为所求。时间复杂度是O(n^3) ,状态转移方程类似Floyd最短路径算法。
代码实现:
class Solution(object):
def maxCoins(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
#先给nums两边加上1,注意list的扩展可用“+”运算符,也可用list.extend(list1)方法
nums = [1] + nums + [1]
n = len(nums)
dp = [[0]*n for _ in range(n)]
for k in range(2, n):
for left in range(0, n-k):
right = left + k
#此时,边界left,right已经确定
for i in range(left+1, right):#不含边界
dp[left][right] = max(dp[left][right], dp[left][i] + nums[left]*nums[i]*nums[right] + dp[i][right])
return dp[0][n-1]
参考: