LeetCode 热题 HOT 100 -------312. 戳气球 (动态规划) 416. 分割等和子集(动态规划)

dsadas在这里插入图片描述
dsadasdasd在这里插入图片描述

/**
这个题我感觉有点歧义,戳破的是第i+1个数,获得nums[i - 1] * nums[i] * nums[i + 1] , 如果i-1或i+1超出了数组的边界,那么就当它是一个数字为1的气球,为了尽可能获得大的,我们应该依次戳破最小的?
不会做,看解析:
dp[i][j]表示在开区间(i,j)能得到硬币数
你在 (i,j) 开区间得到的金币可以由 dp[i][k] 和 dp[k][j] 进行转移
如果你此刻选择戳爆气球 k,那么你得到的金币数量就是:total=dp[i][k]+val[i] * val[k] * val[j]+dp[k][j]
val[i] 表示 i 位置气球的数字 然后 (i,k) 和 (k,j) 也都是开区间
*/
class Solution {
    public int maxCoins(int[] nums) {
        //数组长度
        int n = nums.length;
        //中间数组,把两个边界之外的第一个数都放进去,也就是nums[-1] ,nums[n]
        int[] temp = new int[n+2];
        temp[0] =1;
        temp[n+1] =1;
        for(int i=0 ; i<n ; i++){
            temp[i+1] = nums[i];
        }
        //数组已经建立好了temp
        int[][] dp = new int[n+2][n+2];
        //len表示开区间的长度,动态规划思想,解决小问题->大问题
        for(int len=3 ; len<=n+2 ; len++){
            //i表示开区间左端点
            for(int i = 0 ; i <= n+2-len ; i++ ){
                int res=0;
                //K为开区间内的索引
                for(int k=i+1 ; k < i+len-1 ; k++){
                    int left = dp[i][k];
                    int right = dp[k][i+len-1];
                    res = Math.max(res , left + temp[i] * temp[k] * temp[i+len-1] +right);
                }
                dp[i][i+len-1] = res;
            }
        }
        return dp[0][n+1];
    }
}

416

//首先我们先求出一半的值是多少,并且数组值得和必须是偶数
class Solution {
    public boolean canPartition(int[] nums) {
        int len = nums.length;
        if(len  == 0){
            return false;
        }
        int sum = 0;
        for(int num : nums){
            sum += num;
        }
        if((sum & 1) == 1){
            return false;
        }
        int target = sum / 2;   

        //也就是说求含有target即可,通过动态规划来做
        boolean[][] dp = new boolean[len][target+1];
        //dp[i][j]表示从[0,i]这个子区间中能挑选一些正整数,每个数只能用一次,使得这些数的和恰好等于j
        //先填第0行,第一个数只能让容积为它自己的背包恰好装满(也就是边界)
        if(nums[0] <= target){
            dp[0][nums[0]] = true;
        }
        /*再想转移方程
            不选择nums[i],[0,i-1]这个子区间已经有一部分元素,使得它们的和为j,dp[i][j] =true
            选择nums[i],[0,i-1]这个子区间内的到一部分元素,使得它们的和为j-nums[i] 
        再填后面几行
        */
        for(int i=1 ; i<len ; i++){
            for(int j=1 ; j<=target ; j++){
                //先把上一行抄下来再修正
                dp[i][j] = dp[i-1][j];
                if(nums[i] == j){
                    dp[i][j] = true;
                    continue;
                }
                if(nums[i] < j){
                    dp[i][j] = dp[i-1][j] || dp[i - 1][j - nums[i]];
                }
            }
        }
        return dp[len-1][target];
    }
}

dsadas在这里插入图片描述

//首先我们先求出一半的值是多少,并且数组值得和必须是偶数
class Solution {
    public boolean canPartition(int[] nums) {
        int len = nums.length;
        int sum = 0;
        for(int num : nums){
            sum += num;
        }
        if((sum & 1) == 1){
            return false;
        }
        int target = sum / 2;   

        //也就是说求含有target即可,通过动态规划来做
        boolean[][] dp = new boolean[len][target+1];
        //dp[i][j]表示从[0,i]这个子区间中能挑选一些正整数,每个数只能用一次,使得这些数的和恰好等于j
        //先填第0行,第一个数只能让容积为它自己的背包恰好装满(也就是边界)
        if(nums[0] <= target){
            dp[0][nums[0]] = true;
        }
        /*再想转移方程
            不选择nums[i],[0,i-1]这个子区间已经有一部分元素,使得它们的和为j,dp[i][j] =true
            选择nums[i],[0,i-1]这个子区间内的到一部分元素,使得它们的和为j-nums[i] 
        再填后面几行
        */
        for(int i=1 ; i<len ; i++){
            for(int j=1 ; j<=target ; j++){
                //先把上一行抄下来再修正
                dp[i][j] = dp[i-1][j];
                if(nums[i] == j){
                    dp[i][j] = true;
                    continue;
                }
                if(nums[i] < j){
                    dp[i][j] = dp[i-1][j] || dp[i - 1][j - nums[i]];
                }
            }
        }
        return dp[len-1][target];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值