题目简介:
有 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
示例:
1 | 输入: [3,1,5,8] |
思路:
动态规划,dp[i][j]
代表将开区间(i, j)
内的所有气球戳爆后所能获得的最大硬币数量。
为处理边界问题,先将nums
的最前面和最后面插入1。
由于是开区间,所以i
的取值为0 ~ n - 1
(n
为没插入1前的数组长度),第一个气球为nums[0] = 1
,最后一个气球为nums[n] = 1
,所以若i >= n
,则没有气球可以戳了。
j
的取值为i + 2 ~ n + 1
,若j < i + 2
,则开区间里没有气球可以戳了。
所以在(i, j)
区间里循环定义k
,即k
的取值为i + 1 ~ j - 1
。
k
的左边最大硬币数为dp[i][k]
,k
的右边最大硬币数为dp[k][j]
,将这些气球都戳爆后,最后戳nums[k]
这个气球,获得的硬币数为nums[i] * nums[k] * nums[j]
。(因为一定有一个是最后被戳爆的气球,所以循环遍历,找出硬币数最大值时的那个k
即可)。
所以dp[i][j] = max(dp[i][j], dp[i][k] + dp[k][j] + nums[i] * nums[k] * nums[j])
。
最后返回dp[0][n + 1]
,即不要最开始和最后面我们插入的那两个气球,只要中间的1,2, ..., n
个气球。
tip:
i, j, k
的边界值比较重要,需要理解清楚。
代码如下:
1 | class Solution { |