LeetCode 312 戳气球

 1、看到题目的第一思路

首先想到的是用回溯的方法暴力求解,遍历所有可能的情况。感觉大概率会超出时间限制。

维护全局变量 res 存储当前遍历到的硬币数量的最大值。

1)递归函数参数:当前可戳的气球 balloon,已有的硬币数量 icons(初始化为0)

2)递归函数内容:

(1)如果 balloon 为空,对比当前 icons 与 res,将res更新为最大值

(2)如果 balloon 不为空,遍历各个气球,戳破遍历到的气球,更新icons,调用递归函数。

实现代码如下,感觉必然会超出时间限制

func maxCoins(nums []int) int {
    var res int=0
    var helper func(balloon []int, icons int)

    helper = func(balloon []int, icons int){
        // fmt.Println(balloon, icons)
        if len(balloon)==0{
            res = getMax(res, icons)
        }else{
            var left, right int=1, 1
            for k, v := range balloon{
                if k==0 { left=1 } else { left=balloon[k-1] }
                if k==len(balloon)-1 { right=1 } else { right=balloon[k+1] }
                newBalloon := append([]int{}, balloon[:k]...)
                newBalloon = append(newBalloon, balloon[k+1:]...)
                helper(newBalloon, icons+left*v*right)
            }
        }
    }
    helper(nums, 0)
    return res
}

func getMax(a, b int) int {
    if a>=b {
        return a
    }else { return b }
}

果然超出了时间限制,它要不超可能也不至于在困难类了。

2、想方法减少时间复杂度,两个思路

1)剪枝:考虑什么情况下能够确定当前情况必然不是最优解,想了一下并没有想到。

2)空间换时间:首先想到的就是将之前遍历的情况存储起来,递归之前查看之前已经遍历过的,如果已经存储,证明该种情况已经考虑过,不再进行重复运算,但是也没有想到什么好的解法

3)灵机一动:脑子里动了动,感觉没动出个啥来,看看别的大神怎么解吧,学习一下([LeetCode] 312. Burst Balloons 打气球游戏 - Grandyang - 博客园 (cnblogs.com))。

3、动态规划的思路

果然应该想一下动态的,大意了大意了。动态规划考虑两个方面,子状态(dp数组里存什么)以及状态转移方程(如何根据小的dp数组得到大的dp数组)。

1)子状态:二维数组 dp ,其中dp[i][j],存储戳爆 [i, j] 区间内的全部气球时所能获得的最多硬币

2)状态转移方程:dp[i][j]的值应该为以下两者中的较大值,假设戳 [i, j] 区间中的第k个气球

  • dp[i][j]
  • dp[i][k-1]+dp[k+1][j]+nums[i-1]*nums[k]*nums[j+1](注意:这里在计算硬币时用 nums[i]和nums[j+1]是因为此时区间dp[i][k-1]和dp[k+1][j]之间的气球已经全部戳破)

3)还有一个需要注意的点,通常情况下想到的子状态遍历方法是按照数组的下标进行遍历,但是这里不太一样,是按照区间的长短进行遍历,也就是说首先遍历长度为1所有可能区间,在根据长度为1的区间,计算长度为2区间的所有可能情况,以此类推。

实现代码如下:

func maxCoins(nums []int) int {
    var l int = len(nums)
    var dp [][]int = make([][]int, l+2)
    for k, _:=range dp{ dp[k]=make([]int, l+2) }
    // 首尾添加1,方便计算
    balloons := append([]int{1}, nums...)
    balloons = append(balloons, 1)
    for n:=1; n<=l; n++{    // 从长度为1的区间开始遍历
        for i:=1; i<=l-n+1; i++{    // 区间的开始位置
            j:=i+n-1  // 区间的结束位置
            for k:=i; k<=j; k++{
                dp[i][j]=getMax(dp[i][j], dp[i][k-1]+dp[k+1][j]+balloons[i-1]*balloons[k]*balloons[j+1])
            }
        }
    }
    return dp[1][l]
}

func getMax(a, b int) int {
    if a>=b {
        return a
    }else { return b }
}

注意:一开始划分区间的时候使用了 dp[i][k]+dp[k+1][j]+nums[i-1]*nums[k]*nums[j+1],然后发现自己将切片的下标思想带入了,dp[i][k]区间会将第k个气球戳破,但实际上不应该戳破,应该为dp[i][k-1]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值