Day 39算法记录| 背包问题 05

01背包问题的一维数组和二维的模板

1049.最后一块石头的重量II

讲的很好
最小可能重量:
1.剩余0,就可以看成两个完全相同的背包问题
2. 剩余不是0,要越小越好 = half(+) - half(-) ,这样就可以返回越小的值
从stone中选择石头,使得<=背包容量

1.二维数组

class Solution {
    public int lastStoneWeightII(int[] stones) {
   int n = stones.length;
   int sum =0;
   for(int stone:stones){
       sum +=stone;
   }
   int half = sum>>1;
   int[][] dp = new int[n+1][half+1];

   for(int i=1;i<=n;i++) // 遍历商品
   for(int j =1;j<=half;j++){ //背包容量
   int cur =stones[i-1];
     if( cur>j){   // 装不下
        dp[i][j] = dp[i-1][j];
     }else{
         dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j- cur]+ cur);
     }
   }

   return sum - (dp[n][half]<<1);
    }
}

注意这里dp[i][j]的大小,都是n+1,和 half+1,
dp[i][j] ,表示第i个物品是否放入,对应的是stone[i-1]

2.一维数组

class Solution {
    public int lastStoneWeightII(int[] stones) {
   int n = stones.length;
   int sum =0;
   for(int stone:stones){
       sum +=stone;
   }
   int half = sum>>1;
   int[] dp = new int[half+1];
   
   for(int i =0;i<n;i++){ // 从最开始的商品开始遍历
   int cur =  stones[i];
     for(int j = half;j>=cur;j--){
         dp[j] = Math.max(dp[j],dp[j-cur]+cur);
     }
   } 
   return sum -2*dp[half];
    }
}

494. 目标和

转换为背包问题:
视频解析:
相当于将一个数组分成两部分,一部分前面加“+”,之和为 x x x,另一部分“ - ”,绝对值之和为 y y y
数组之和 s u m sum sum = x x x + y y y t a r g e t target target = x x x - y y y, x x x = ( s u m + t a r g e t ) (sum+target) (sum+target)/2
所以问题转换为: 一个背包容量为x,装满的方式有几种的问题了

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
    
    int sum =0;
    for(int num:nums){
      sum += num;
    }

    if(sum<target||-sum>target || (sum+target)%2 != 0){
        return 0;
    }

    int x = (sum+target)>>1;
    int[] dp = new int[x+1];
    dp[0] =1;       //填满背包容器为0的方式只有1种
    for(int i =0;i<nums.length;i++){
        int cur = nums[i];
        for(int j = x;j>= cur;j--){
           dp[j] = dp[j] + dp[j-cur]; //有几种,就是选和不选,选就是dp[j-cur] ,不选就是dp[j]
        }
    }
    return dp[x];
    }
}

474. 一和零

这道题是多背包问题,所以就对应有三维数组和二维数组的两种方式
三维数组的方式:
主要还是以二维为主:

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
     
     int[][] dp = new int[m+1][n+1]; //1.dp[i][j] 分别表示在i放入0,j放入1的时候,最多的个数
     //初始化

     for(String str : strs){  //开始按照物品遍历
        // 1.统计每个元素中0和1的个数
        int zeros =0; int ones =0;
        for(char ch: str.toCharArray()){
            if(ch == '0'){
                zeros++;
            }else{
                ones++;
            }
        }
        //开始对当前物品装包
         for(int i = m; i >= zeros; --i) {
                for(int j = n; j >= ones; --j) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - zeros][j - ones] + 1);
                }
            }
     }
          return dp[m][n];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值