zoukankan      html  css  js  c++  java
  • LeetCode312. Burst Balloons

    Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent.

    Find the maximum coins you can collect by bursting the balloons wisely.

    Note:

    • You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
    • 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

    Example:

    Input: [3,1,5,8]
    Output: 167 
    Explanation: 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

    思路

    解法有backtrack和dp两种,首先还是来分析题目。

    这题的要素有:n 个气球,从0到n-1编号,每个气球都标记了一个硬币数字。戳爆其中一个会得到指定的coings,与相邻的两个数字的乘积是所获得的硬币数。那么如何确定戳爆顺序使得获得的硬币数目最大?难点在于不同的戳爆顺序会相互影响。

    从最后戳爆的气球位置入手,如果最后戳爆的气球是位置i上的气球,那么可以肯定的是在它之前的 0~i-1 位置上的气球肯定被戳爆了,i+1到n-1位置上的气球也被戳爆了。递归遍历所有的i即可。

    public int maxCoins(int[] iNums) {
        int[] nums = new int[iNums.length + 2]; // 构造新数组,方便计算
        int n = 1;
        for (int x : iNums) if (x > 0) nums[n++] = x;
        nums[0] = nums[n++] = 1;  // 这里一直用n++是因为要忽视iNums的0,这样n最后不一定等于iNum的长度
    
    
        int[][] memo = new int[n][n]
        return burst(memo, nums, 0, n - 1); // 从1到n-1位置上搜索,即left+1~right,之所以n-1是因为上面的n++使得n到了末尾1的后一位
    }
    
    public int burst(int[][] memo, int[] nums, int left, int right) {
        if (left + 1 == right) return 0;  // 如果left+1==right,因为是从left+1到right-1处遍历的。遍历结束,直接返回
        if (memo[left][right] > 0) return memo[left][right];  // 如果已计算过,则不需再次计算
        int ans = 0;
        for (int i = left + 1; i < right; ++i) // 初始从left+1到right-1,对应起来正好是iNums中的0~n-1
            ans = Math.max(ans, nums[left] * nums[i] * nums[right] 
            + burst(memo, nums, left, i) + burst(memo, nums, i, right));
        memo[left][right] = ans;
        return ans;
    }

    DP解法如下:

    public int maxCoins(int[] iNums) {
        int[] nums = new int[iNums.length + 2];
        int n = 1;
        for (int x : iNums) if (x > 0) nums[n++] = x;
        nums[0] = nums[n++] = 1;
    
        int[][] dp = new int[n][n];
    
     // k表示计算步长,从right=left+2开始。因为i从left+1到right-1遍历,所以一开始只计算left和right之间只隔了一位的情况
        for (int k = 2; k < n; ++k)
                for (int left = 0; left < n - k; ++left) {
                int right = left + k;
                for (int i = left + 1; i < right; ++i)  // 在子问题dp[left][right]下,遍历每个可能的最后引爆的气球,以求出子问题的最优解
                    dp[left][right] = Math.max(dp[left][right], 
                    nums[left] * nums[i] * nums[right] + dp[left][i] + dp[i][right]);  // 左边界是left,右边界是right
            }
    
        return dp[0][n - 1];
    }        
  • 相关阅读:
    H5项目开发分享——用Canvas合成文字
    《JavaScript设计模式 张》整理
    Linux常用指令指南,终端装逼利器
    飞起来的正则表达式
    JavaScript特性(attribute)、属性(property)和样式(style)
    使用 Nginx 提升网站访问速度
    centos 邮件服务 腾讯企业邮箱(免费) 使用iRedmail 需要有公网的centos主机 发邮件协议:smtp 端口25 收邮件协议:pop3 端口110 iredmail安装配置 使用邮箱系统 第三十一节课
    用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面
    mysql字符集调整总结
    因为smb和nfs挂掉导致客户端开机启动不了
  • 原文地址:https://www.cnblogs.com/f91og/p/9509125.html
Copyright © 2011-2022 走看看