动态规划 Leetcode 312 Burst Balloons(戳气球)

本文详细解析了一道经典动态规划问题——戳破气球获得最大硬币数的算法思路,通过逐步填充矩阵的方式,展示了如何计算最优解,适用于算法初学者和面试准备者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

有 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

示例:

输入: [3,1,5,8]

输出: 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

链接(中文版):https://leetcode-cn.com/problems/burst-balloons

链接(英文版):https://leetcode.com/problems/burst-balloons

分析

根据题目说明,先在两边各加一个1,即:1 3 1 5 8 1

如果最后戳破的气球是1,则蓝的3 5 8已经被戳破了,即:1 3 1 5 8 1,此时戳破1得到的分数是:戳破左边的3得到的最高分数+戳破右边的5 8得到的最高分数+(1 * 1 * 1)。根据动态规划的思想,戳破左边的3得到的最高分数戳破右边的5 8得到的最高分数都已经事先计算得到了。

用如下6*6的矩阵M表示最优结果,黑色的数字是行号和列表。

M[0][2](红色X)表示把序号0到2之间的气球戳破的最高分数,即上述戳破左边的3得到的最高分数

M[2][5](绿色X)表示把序号2到5之间的气球戳破的最高分数,即上述戳破右边的5 8得到的最高分数

我们需要的最终答案是M[0][5](黑色的X),即戳破序号0到5之间的气球戳破的最高分数

 012345
0  X  X
1      
2     X
3      
4      
5      

 

矩阵M初始化为全零,接下来一步一步完成和这个矩阵的填充。

戳破1个气球

需要从无法再细分的子问题开始计算,即只戳破一个气球的时候,上述戳破左边的3得到的最高分数就是一个无法在细分的子问题。这个结果可以直接计算出来,即M[0][2]=1*3*1=3。

然后M[1][3]=3*1*5=15,M[2][4]=1*5*8=40,M[3][5]=5*8*1=40,此时矩阵内容如下。

 012345
0  3   
1   15  
2    40 
3     40
4      
5      

戳破2个连续的气球

然后计算戳破2个连续的气球的最高分数M[0][3]、M[1][4]和M[2][5]。

M[0][3]=max(M[0][3], nums[0]*nums[i]*nums[3]+M[0][i]+M[i][3]),i的取值是1和2。M[0][3]初始是0。当i=1时,表示最后戳破编号为1的气球,此时区间0到3之间其余的气球已经都戳破了,就剩编号为1的气球了,因此得分是nums[0]*nums[1]*nums[3]。然后加上已经戳完的左边的气球最佳得分M[0][1](编号0和1之间有0个气球,因此M[0][1]=0,这个是初始化得到的)以及已经戳完的右边的气球最佳得分M[1][3](M[1][3]=15是上文计算得到的)。

因此当i=1时,M[0][3]=max(0, 1*3*5+0+15)=30。

同理当i=2时,M[0][3]=max(M[0][3], nums[0]*nums[2]*nums[3]+M[0][2]+M[2][3])=max(30, 1*1*5+3+0)=max(30, 8)=30。

接着求出其余的M[1][4]和M[2][5],此时矩阵内容如下。

 012345
0  330  
1   15135 
2    4048
3     40
4      
5      

 

戳破3个连续的气球

然后计算戳破3个连续的气球的最高分数M[0][4]和M[1][5],矩阵内容如下。

 012345
0  330159 
1   15135159
2    4048
3     40
4      
5      

戳破4个连续的气球

然后计算戳破4个连续的气球的最高分数M[0][5],矩阵内容如下。黑色的167即为最终结果。

 012345
0  330159167
1   15135159
2    4048
3     40
4      
5      

 

代码

import numpy as np

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        nums = [1] + nums + [1]
        n = len(nums)
        M = np.zeros((n, n), dtype=np.int)

        for k in range(2, n): #k=2时是计算戳破1个气球的最优解,k=3时事计算戳破2个连续的气球的最优解。。。
            for a in range(0, n-k): #a是被戳破的连续K-1个气球的区间的左边,a+k是区间的右边
                for i in range(a+1, a+k): #i就是上述分析中的i
                    M[a][a+k] = max(M[a][a+k], M[a][i] + M[i][a+k] + nums[a] * nums[i] * nums[a+k])
        return M[0][-1]

总结

这道题和矩阵连乘很像,关键是找出计算子问题的顺序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值