【LeetCode】每日一题(二十五)312. 戳气球 动态规划 区间dp

312. 戳气球

20200719

难度:困难

题目描述

有 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

Solution

动态规划 区间dp

  • 状态:dp[i][j]代表戳破[i,j]的气球所能获得硬币的最大数量。

  • 状态转移:枚举区间——左端点——最后一个戳破的气球

    dp[i][j] = Math.max(dp[i][j], dp[i][k-1] + dp[k+1][j] + expand[i-1] * expand[k] * expand[j+1]);

class Solution {
    public int maxCoins(int[] nums) {
        if(nums == null || nums.length == 0){
            return 0;
        }
        int n = nums.length;
        int[][] dp = new int[n+2][n+2];
        //扩展nums[-1] = nums[n] = 1
        int[] expand = new int[n+2];
        expand[0] = 1;
        expand[n+1] = 1;
        for(int i = 0; i < n; i++){
            expand[i+1] = nums[i];
        }

        for(int len = 1; len <= n; len++){//枚举区间
            for(int i = 1; i + len - 1 <= n; i++){//左端点
                int j = i + len - 1;//右端点
                for(int k = i; k <= j; k++){//枚举最后一个戳破的气球
                    dp[i][j] = Math.max(dp[i][j], dp[i][k-1] + dp[k+1][j] + expand[i-1] * expand[k] * expand[j+1]);
                }
            }
        }
        return dp[1][n];
    }
}

欢迎关注公众号:GitKid,暂时每日分享LeetCode题解,在不断地学习中,公众号内容也在不断充实,欢迎扫码关注

你可能感兴趣的:(数据结构与算法,LeetCode)