312戳气球
题目:有 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
来源:https://leetcode-cn.com/problems/burst-balloons/
法一:自己的代码 动态规划
思路:这是一道区间dp题,与1000合并石头的最低成本方法类似,都是由内到外进行数据记录,关键是写出动态规划方程,注意使用动态方程的时候一定不要拘泥于只用一维dp,要根据题意进行选择,本题要求的是数组从0到n的最大值,而0和n就是决定最后结果的两个变量,故用它们定义二维动态数组,从i到j的最大值是由未戳破的k加上其余已经戳破的数组的和决定的,由此写出如下的状态转移方程.
dp[i][j] = max(nums[i-1] * nums[k] * nums[j+1] + dp[i][k-1] + dp[k+1][j] for k in range(i,j+1))
要学会斜变量dp矩阵的方法.
from typing import List class Solution: def maxCoins(self, nums: List[int]) -> int: ans = 0 # 为了方便后续写状态转移方程,添加边界条件 nums = [1] + nums + [1] size = len(nums) dp = [[0] * size for i in range(size)] # 这里提供了一个斜遍历矩阵的方法,start用于控制起始位置,引入变量i进行控制行索引 for start in range(1,size): i = 1 print('-' * 20) for j in range(start,size-1): print(i,j) # 最开始的这个状态转移方程是错的,只考虑了i,j数据两边未戳破的情况,事实上中间也有可能未戳破,与两边已经戳破的进行合并. # dp[i][j] = max(nums[i-1] * nums[i] * nums[j+1] + dp[i+1][j], # nums[i-1] * nums[j] * nums[j+1] + dp[i][j-1]) dp[i][j] = max(nums[i-1] * nums[k] * nums[j+1] + dp[i][k-1] + dp[k+1][j] for k in range(i,j+1)) i += 1 print(dp) return (dp[1][size-2]) if __name__ == '__main__': duixiang = Solution() # a = duixiang.maxCoins([3,1,5,8]) a = duixiang.maxCoins([35, 16, 83, 87, 84, 59, 48, 41]) print(a)
ttt