312. Burst Balloons

LeetCode

  • 题目地址:https://leetcode.com/problems/burst-balloons/#/description
  • 题目描述&解题思路:给n个气球,每个气球有一个数字,用一个数组nums表示这些数字。戳破这个气球i可以得到nums[i]*nums[i-1]*nums[i+1]个硬币,可以假设nums[-1]和nums[n]=1。 求能获得的最大硬币个数。

    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

    解决办法是动态规划,假设的dp[left][right]表示left到right区间,能获得的最大的硬币个数。本题的关键是找到最后一个戳的气球是哪个。要关注的点如下:

    1. dp[left][right]表示先戳破这个区间的气球,最多能得到多少个硬币,即在left到right区间内,最后一个戳破的气球k得到的硬币是nums[k]*nums[left-1]*nums[right+1]
    2. 计算dp[left][right]需要,任意a,b属于[left,right],dp[a][b],即从长度入手,先算长度小的再算长度大的
    3. 递推公式,找到气球k,是left到right区间内最后一个戳破的,那么dp[left][right] = max(dp[left][right],nums[left-1]*nums[k]*nums[right+1]+dp[left][k-1]+dp[k+1][right])
    4. 实现中的小技巧,可以把收尾的nums[-1]=nums[n]=1先插入数字,这样数组长度变成n+2,这时候不需要对边界做特殊处理
  • 代码如下:

class Solution {
public:
    int max(int a, int b) {
        return a > b ? a : b;
    }
    int maxCoins(vector<int>& nums) {
        //插入首尾两个1
        int size = nums.size();
        nums.insert(nums.begin(),1);
        nums.push_back(1);
        //记忆存储 加速dp
        //插入两个1后,nums.size() = size + 2
        vector<vector<int>> dp(size + 2, vector<int>(size + 2, 0));
        //先算len = right-left+1小的,再算大的
        for (int len = 0; len < size; len++) {
            for (int left = 1; left <= size - len; left++) {
                int right = left + len;
                //left到right最后一个戳破的气球k
                for (int k = left; k <= right; k++) {
                    dp[left][right] = max(dp[left][right], nums[left-1]*nums[k]*nums[right+1] + dp[left][k-1] + dp[k+1][right]);
                }
            }
        }
        return dp[1][size];
    }
};

你可能感兴趣的:(LeetCode)