leetcode 312. 戳气球

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

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

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

 

题解:

1.n 个气球

2.戳破气球 i ,就可以获得 nums[left] * nums[i] * nums[right] 个硬币,left 和 right 与 i 相邻

3.戳破 i 后,气球 left 和气球 right 相邻

4.这里戳破气球的选择顺序有很多,结果是能得到最大硬币数量的方式计算

 

说明:

你可以假设 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 =  3*1*5      +  3*5*8    +  1*3*8      + 1*8*1   = 167

 

解题思路:

  • 因为要考虑到头尾元素1,重建一维容器把这两个元素加进去

  • 考虑使用一个二维容器记录中间结果,减少递归过程中重复计算值

  • 把新建的数组从头到尾不断一分为二的递归计算和值,有重复计算数值内容直接返回数组元素

  • 题目要求最大数量,每次递归计算出和值都选取较大者,保证最后整个数组获得最大硬币数量

C/C++题解:

class Solution {

public:

    vector<vector<int>> rec;

    vector<int> val;

    int solve(int left, int right) {

        if (left >= right - 1) {//左右双指针

            return 0;

        }//如果已经计算过了值,直接从数组返回减少重复计算

        if (rec[left][right] != -1) {

            return rec[left][right];

        }//从左边界到右边界,从第二个元素计算

        for (int i = left + 1; i < right; i++) {

            int sum = val[left] * val[i] * val[right];

            sum += solve(left, i) + solve(i, right);//左右分别进一步计算

            rec[left][right] = max(rec[left][right], sum); }//选出最大数量

 

        return rec[left][right];}

    int maxCoins(vector<int>& nums) {

        int n = nums.size();

        val.resize(2,1);//把数组index=-1,n的位置为1补齐

        val.insert(val.begin() + 1, nums.begin(), nums.end());

        //-1初始化记忆容器,注意加了头尾元素1

        rec.resize(n + 2, vector<int>(n + 2, -1));

        return solve(0, n + 1); }};

Debug结果:

Java题解:

class Solution {

    public int[][] rec;

    public int[] val;

    public int solve(int left, int right) {

        if (left >= right - 1) {//左右双指针  return 0;

        }//如果已经计算过了值,直接从数组返回减少重复计算

        if (rec[left][right] != -1) {

            return rec[left][right];

        }//从左边界到右边界,从第二个元素计算

        for (int i = left + 1; i < right; i++) {

            int sum = val[left] * val[i] * val[right];

            sum += solve(left, i) + solve(i, right);//左右分别进一步计算

            rec[left][right] = Math.max(rec[left][right], sum); }//选出最大数量

 

        return rec[left][right]; }

    public int maxCoins(int[] nums) {

        int n = nums.length;

        val = new int[n + 2];

        for (int i = 1; i <= n; i++) {

            val[i] = nums[i - 1]; }

        val[0] = val[n + 1] = 1;//把数组index=-1,n的位置为1补齐

        //-1初始化记忆容器,注意加了头尾元素1

        rec = new int[n + 2][n + 2];

        for (int i = 0; i <= n + 1; i++) {

            Arrays.fill(rec[i], -1); }

        return solve(0, n + 1); }}

Debug结果:

Python题解:

class Solution(object):

    def maxCoins(self, nums):

        """:type nums: List[int]:rtype: int"""

        rec = [[-1 for _ in range(len(nums)+2)] for _ in range(len(nums)+2)]

        val = [1] + nums + [1]

        def solve(left, right):

            if left >= right - 1: #左右双指针

                return 0

            #如果已经计算过了值,直接从数组返回减少重复计算

            if rec[left][right] != -1:

                return rec[left][right]

            #从左边界到右边界,从第二个元素计算

            for i in range(left+1, right):

                count = val[left] * val[i] * val[right]

                count += solve(left, i) + solve(i, right) #左右分别进一步计算

                rec[left][right] = max(rec[left][right], count) #选出最大数量

            return rec[left][right]

        return solve(0, len(nums)+1)

Debug结果:

更多题解移步公众号免费获取

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值