• 312. Burst Balloons


    入手的时候一直想打破表面,发现数学本质,结果并没有发现什么数学本质,直接去找答案。

    挺复杂的,一般H的题如果我面试的时候遇到,用成语形容可能出现的情况,就是我可能会吃屎。这题对我来说是一定会吃屎

    dietpepsi给的答案很详细。

    首先,一排气球左边是L,右边是R,我们可以假设最后一个打爆的气球是i,那倒数第二个打爆的气球j就出现在L-i或者i-R.

    dp[L][R] = nums[i] * nums[L] * nums[R] + dp[L][i]+dp[i][R];

    dp[L][R]表示从L打到R的最终得分。
    nums[i] * nums[L] * nums[R]表示最后一次得分,这里我们已经假设L到i之间,i到R之间气球已经都打爆了。
    刚才假设的内容,L到I之间,I到R之间都已经打爆了,但是我们没有加分,所以要加上dp[L][i]+dp[i][R],其实就是最后一个气球之前的气球。

    DP[L][R]的时候要遍历,看看最后打哪个最合算,有很多重复计算,可以用DP记住。

    dietpepsi的解释里面做了很多假设,看完之后我真射了。

    题很难,如果不是碰到原题,面试遇到只能认栽。个人感觉更重要的是dietpepsi提供了很详细地思考过程,怎么一步一步思考找到答案,如何从n!到n^3。值得一看,可能比做出这一道题更重要:
    (https://discuss.leetcode.com/topic/30746/share-some-analysis-and-explanations)

    
    public class Solution 
    {
        public int maxCoins(int[] oldnums) 
        {
            int[] nums = new int[oldnums.length+2];
            int index = 1;
            nums[0] = 1;
            for(int i: oldnums) nums[index++] = i;
            nums[index] = 1;
            
            int[][] dp = new int[nums.length][nums.length];
            
            return helper(nums,0,nums.length-1,dp);
        }
        
        public int helper(int[] nums, int left, int right, int[][] dp)
        {
            if(dp[left][right]!=0) return dp[left][right];
            
            int res = 0;
            
            for(int i = left+1;i < right;i++)
            {
                res = Math.max(dp[left][right],
                                    helper(nums,left,i,dp)+
                                    helper(nums,i,right,dp)+
                                    nums[i]*nums[left]*nums[right]);
                                    
                dp[left][right] = res;
            }
            
            
            return res;
        }
        
    }
    

    还有个更DP的做法,没理解,二刷再说。



    二刷

    二刷还是做晕了,今天状态好差,这几个H难度的题都只是理解做法了,但是并没有归纳总结出什么general的DP思想,DP对我来说千变万化。。。

    这个题必须这么考虑。

    Left score1 score2 score3 .... scoreN Right
    假设有这么多气球,最边上2个left, right是1.

    假设此时就剩1个气球,let's say its score3.

    那么这最后一轮的得分是score3 * 他左边 * 他右边, 因为它是最后一个,他左右是Left和Right,都是1. 最后一轮得分,score3

    倒数第二轮的情况就不一定了,他可能是是在(Left, score3)这个范围内,也可能在(left3, Right)这个范围内。
    但是有一点肯定,不管是score3左边的区间,还是右边的区间,只要有气球被打爆,就加分。。 所以要加上递归那2个区间的结果。。
    当前得分 + 左边区间得分 + 右边区间得分

    在每次进入递归,然后算此区间打哪个气球最合算。

    这里“打哪个气球”,是假设打的这个气球是此去见的最后一个,所以都要乘以当前区间的左右边界,而不是相邻的2个气球。

    这里一开始搞乱了。。

    public class Solution {
        public int maxCoins(int[] nums) {
            if (nums.length == 0) return 0;
            
            int len = nums.length;
            int[] scores = new int[len+2];
            
            scores[0] = 1;
            scores[len + 1] = 1;
            
            for (int i = 0; i < len; i++) {
                scores[i+1] = nums[i];
            }
            int[][] mem = new int[len+2][len+2];
            
            return calScore(1, len, scores, mem);
        }
        
        public int calScore(int l, int r, int[] scores, int[][] mem) {
            if (mem[l][r] != 0) return mem[l][r];
            int tempMax = 0;
            for (int i = l; i <= r; i++) {
                int leftScore = calScore(l, i-1, scores, mem);
                int rightScore = calScore(i+1, r, scores, mem);
                int tempScore = scores[l-1] * scores[i] * scores[r+1];
                tempMax = Math.max(tempMax, leftScore + rightScore + tempScore);
            }
            mem[l][r] = tempMax;
            return tempMax;
        }
    }
    
  • 相关阅读:
    接口常用code码
    vscode 开发项目, Prettier ESLint的配置全攻略(基础篇)
    SpringBoot 阿里云OSS 上传和删除
    Vue2 配置跨域
    关于《 MultipartFile 的 file.transferTo 》 的坑
    SQL Server collation introduction with collate SQL casting Baron
    大数据如何进大厂全流程详解【附资料】
    行业领先的界面控件包DevExpress 3月正式发布v21.2.6
    B/S端界面控件DevExtreme ASP.NET MVC入门指南 指定选项(二)
    界面控件DevExpress WinForms v21.2亮点 富文本编辑器功能升级
  • 原文地址:https://www.cnblogs.com/reboot329/p/5891265.html
Copyright © 2020-2023  润新知