题目
有 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 = 315 + 358 + 138 + 181 = 167
//观察执行思路
//递归最后会形成一个类型树的调用,从树的底部开始返回,一次取最大的,借助图形就很好理解了
func maxCoins(nums []int) int {
n := len(nums)
val := make([]int, n + 2)
for i := 1; i <= n; i++ {
val[i] = nums[i - 1]
}
val[0], val[n+1] = 1, 1
//二维数组
rec := make([][]int, n + 2)
for i := 0; i < len(rec); i++ {
//对二维数组初始化,全部赋值为-1
rec[i] = make([]int, n + 2)
for j := 0; j < len(rec[i]); j++ {
rec[i][j] = -1
}
}
return solve(0, n + 1, val, rec)
}
func solve(left, right int, val []int, rec [][]int) int {
if left >= right - 1 {
return 0
}
if rec[left][right] != -1 {
return rec[left][right]
}
//0-5
for i := left + 1; i < right; i++ {
//把每个数对应的硬币量算出出来
sum := val[left] * val[i] * val[right]
//分治,先算当前在算两边的
sum += solve(left, i, val, rec) + solve(i, right, val, rec)
//取较大的
rec[left][right] = max(rec[left][right], sum)
}
return rec[left][right]
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
//动态规划
func maxCoins(nums []int) int {
n := len(nums)
rec := make([][]int, n + 2)
for i := 0; i < n + 2; i++ {
rec[i] = make([]int, n + 2)
}
val := make([]int, n + 2)
val[0], val[n+1] = 1, 1
for i := 1; i <= n; i++ {
val[i] = nums[i-1]
}
for i := n - 1; i >= 0; i-- { //从右边第一个有效数开始
for j := i + 2; j <= n + 1; j++ {
for k := i + 1; k < j; k++ {
sum := val[i] * val[k] * val[j]
sum += rec[i][k] + rec[k][j]
rec[i][j] = max(rec[i][j], sum)
}
}
}
return rec[0][n+1]
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
参考地址:https://leetcode-cn.com/problems/burst-balloons/solution/chuo-qi-qiu-by-leetcode-solution/