312 戳气球

本文最后更新于:2022年4月9日 中午


n 个气球,编号为0n-1,每个气球上都标有一个数字,这些数字存在数组 nums 中。

现在要求你戳破所有的气球。如果你戳破气球 i ,就可以获得 nums[left] * nums[i] * nums[right] 个硬币。 这里的 leftright 代表和 i 相邻的两个气球的序号。注意当你戳破了气球 i 后,气球 left 和气球 right 就变成了相邻的气球。

求所能获得硬币的最大数量。

说明:

  • 你可以假设 nums[-1] = nums[n] = 1,但注意它们不是真实存在的所以并不能被戳破。
  • 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

示例:

1
2
3
4
输入: [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

Solution

参考:《算法小抄》2.14

  • dp[i] [j] = x,表示戳破气球 i 和气球 j 之间的所有气球,那么可以获得的最高分数为 x。

  • 状态转移方程:

    dp[i][j] = dp[i][k] + dp[k][j] + points[i]*points[k]*points[j]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# @lc code=start
class Solution:
def maxCoins(self, nums: List[int]) -> int:
n = len(nums)
points = [0]*(n+2)
points[0] = points[n+1]=1
for i in range(1,n+1):
points[i] = nums[i-1]

dp = [[0 for _ in range(n+2)] for _ in range(n+2)]
for i in range(n,-1,-1):
for j in range(i+1,n+2):
for k in range(i+1, j):
dp[i][j] = max(dp[i][j], dp[i][k]+dp[k][j]+points[i]*points[j]*points[k])
return dp[0][n+1]
# @lc code=end

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!