312题-戳气球

题目

有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 = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167

解答

这里我打算采用动态规划方法,但是我们发现,当存在四个以上的数的时候,在取掉中间的数时,根据题目要求并不是分为两部分,而是合并到一起形成一个新数组,所以子问题不独立。所以我们需要换一种方式进行状态转移。在区间i-j中,我们寻找最后戳破的气球是得dp[i][j]最大。这里和前面我们选择最先戳破中间k不同。因为k是最后戳破的,所以i到k-1和k+1到j仍然是独立的子问题。状态转移方程为:dp[left][right] = dp[left][i]+dp[i][right]+arr[left] * arr[i] * arr[right]。

代码

class Solution {
    public int maxCoins(int[] nums) {
        int len = nums.length+2;
        int[] arr = new int[len];
        System.arraycopy(nums,0,arr,1,nums.length);
        arr[0] = 1;
        arr[len-1] = 1;
        int[][] dp = new int[len][len];
        for(int gop = 2; gop <len; gop++){
            for(int left = 0; left<len-gop; left++){
                int right = left+gop;
                int conis = 0;
                for(int i = left+1; i < right;i++){
                    conis = Math.max(conis,dp[left][i]+dp[i][right]+arr[left]*arr[i]*arr[right]);
                }
                dp[left][right] = conis;
            }
        }
        return dp[0][len-1];
    }
}
posted @ 2020-07-19 07:34  大嘤熊  阅读(190)  评论(0编辑  收藏  举报