• leetcode312


    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 rightare 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

    DP。O(n^3)
    考虑消去型的dp,不好正面想消去后接下来怎么处理,要反过来想。先想最后一个消去的对象能得多少分,想最后一个对象消哪一个能让答案为最大值。
    本题有一个特点:左右区间独立。消去最后一个气球时,气球左边的区间消去最优得分和气球右边的区间完全没关系。这是因为两边的气球被中间这个气球隔开了,左边区间最后一个气球分数才用到中间这个气球,再左边的气球更用不到中间及以后的气球了。利用这个特性,如果我们在[i,j]这段区间中间的k位置扎破最后一个气球,那么得分关系就有point[i,j] = point[i,k] + point[k,j] + 扎k得分。

    dp[i][j]定义:区间[i, j]中扎气球能得的最大分数,保证i, j不被扎破。
    初始化:所有长度为2的区间如dp[i, i+1]都初始化为0,因为两个边缘气球不能被扎破。
    递推公式:dp[i][j] = Max(dp[i][k] + dp[k][j] + nums[i] * nums[k] * nums[j]), 对所有满足i < k < j 的k遍历。


    细节:
    1.区间型动态规划的推导顺序,最外层按区间长度循环渐增。然后内部先根据起始点i循环,由i和len可以直接得到j。i的循环条件根据j的下标要在什么范围内可以推得。
    2.最开始先对nums扩充一下左右两边比较好,也就是最左边和最右边有一个nums[i] == 1的不能扎破的气球,这样好算原始数据里最边缘两个气球被扎破时的得分。

    实现:

    class Solution {
        public int maxCoins(int[] nums) {
            if (nums == null || nums.length == 0) {
                return 0;
            }
            
            int[][] dp = new int[nums.length + 2][nums.length + 2];
            int[] temp = new int[nums.length + 2];
            temp[0] = temp[temp.length - 1] = 1;
            for (int i = 0; i < nums.length; i++) {
                temp[i + 1] = nums[i];
            }
            nums = temp;
            
            dp[0][0] = 0;
            for (int i = 1; i < dp.length; i++) {
                dp[i][i] = 0;
                dp[i - 1][i] = 0;
            }
            
            
            for (int dist = 2; dist <= dp.length - 1; dist++) {
                for (int i = 0; i + dist < dp[0].length; i++) {    
                    int j = i + dist;
                    dp[i][j] = 0;
                    for (int k = i + 1; k < j; k++) {
                        dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[k][j] + nums[i] * nums[k] * nums[j]);
                    }
                }
            }
            return dp[0][dp[0].length - 1];
            
        }
    }
  • 相关阅读:
    共享纸巾更换主板代码分析 共享纸巾主板更换后的对接代码
    Python Django Ajax 传递列表数据
    Python Django migrate 报错解决办法
    Python 创建字典的多种方式
    Python 两个list合并成一个字典
    Python 正则 re.sub替换
    python Django Ajax基础
    Python Django 获取表单数据的三种方式
    python Django html 模板循环条件
    Python Django ORM 字段类型、参数、外键操作
  • 原文地址:https://www.cnblogs.com/jasminemzy/p/9660227.html
Copyright © 2020-2023  润新知