Leetcode416/1049/494之01背包类型的例题
Leetcode416-分割等和子集
- 给你一个 只包含正整数 的 非空 数组 nums。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
- 输入:nums = [1,5,11,5]
- 输出:true
//二维数组版
  public boolean canPartition(int[] nums) {
        int sum = 0;
        int maxNum = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            maxNum = Math.max(maxNum, nums[i]);
        }
        if (sum % 2 == 1 || nums.length == 1 || maxNum > sum / 2) {
            return false;
        }
        int target = sum / 2;
        boolean[][] dp = new boolean[nums.length][target + 1];
        for (int i = 0; i < nums.length; i++) {
            dp[i][0] = true;
        }
        dp[0][nums[0]] = true;//其余都默认false
        for (int i = 1; i < nums.length; i++) {
            int num = nums[i];
            for (int j = 1; j <= target; j++) {
                if (j >= num) {
                    dp[i][j] = dp[i - 1][j] | dp[i - 1][j - num];
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[nums.length - 1][target];
    }
//一维数组版
 public boolean canPartition2(int[] nums) {
        int sum = 0;
        int maxNum = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            maxNum = Math.max(maxNum, nums[i]);
        }
        //先进行一遍筛选
        if (sum % 2 == 1 || nums.length == 1 || maxNum > sum / 2) {
            return false;
        }
        int target = sum / 2;
        //定义dp数组
        boolean[] dp = new boolean[target + 1];
        //初始化
        dp[0] = true;
        //遍历
        for (int i = 0; i < nums.length; i++) {
            //因为是01背包问题 所以此处倒序
            for (int j = target; j >= nums[i]; j--) {
                dp[j] = dp[j] || dp[j - nums[i]];
            }
        }
        return dp[target];
    }
Leetcode1049-最后一块石头的重量二
- 有一堆石头,用整数数组 stones表示。其中stones[i]表示第i块石头的重量。
- 每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x和y,且x <= y。那么粉碎的可能结果如下:- 如果 x == y,那么两块石头都会被完全粉碎;
- 如果 x != y,那么重量为x的石头将会完全粉碎,而重量为y的石头新重量为y-x。
 
- 如果 
- 最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。
- 输入:stones = [2,7,4,1,8,1]
- 输出:1
//二维数组版
    public int lastStoneWeightII(int[] stones) {
        int totalWeight = 0;
        for (int i = 0; i < stones.length; i++) {
            totalWeight += stones[i];
        }
        int targetSum = totalWeight / 2;
        int[][] dp = new int[stones.length][targetSum + 1];
        for (int i = 0; i <= targetSum; i++) {
            if (i >= stones[0]) {
                dp[0][i] = stones[0];
            }
        }
        for (int i = 1; i < stones.length; i++) {
            int tempStone = stones[i];
            for (int j = 1; j <= targetSum; j++) {
                if (j >= tempStone) {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - tempStone] + tempStone);
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        int restSum = totalWeight - dp[stones.length - 1][targetSum];
        return restSum - dp[stones.length - 1][targetSum];
    }
//一维数组版
 public int lastStoneWeightII2(int[] stones) {
        int totalWeight = 0;
        for (int i = 0; i < stones.length; i++) {
            totalWeight += stones[i];
        }
        int targetSum = totalWeight / 2;
        int[] dp = new int[targetSum + 1];
        for (int i = 0; i < stones.length; i++) {
            for (int j = targetSum; j >= stones[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
            }
        }
        return totalWeight - 2 * dp[targetSum];
    }
Leetcode494-目标和
- 给你一个整数数组 nums和一个整数target。
- 向数组中的每个整数前添加 '+'或'-',然后串联起所有整数,可以构造一个 表达式 :- 例如,nums = [2, 1],可以在2之前添加'+',在1之前添加'-',然后串联起来得到表达式"+2-1"。
 
- 例如,
- 返回可以通过上述方法构造的、运算结果等于 target的不同 表达式 的数目。
- 输入:nums = [1,1,1,1,1], target = 3
- 输出:5
 //递归法
    int res=0;
    public int findTargetSumWays(int[] nums, int target) {
        getSum(nums,target,0,0);
        return res;
    }
    public void getSum(int[] nums,int target,int sum,int startIndex){
        if(startIndex==nums.length){
            if(sum==target){
                res++;
            }
            return;
        }
        sum+=nums[startIndex];
        getSum(nums,target,sum,startIndex+1);
        sum-=nums[startIndex];
        sum-=nums[startIndex];
        getSum(nums,target,sum,startIndex+1);
        sum+=nums[startIndex];
    }
    @Test
    public void test(){
        int[] nums=new int[]{1,1,1};
        int target=1;
        int targetSumWays = findTargetSumWays(nums, target);
        System.out.println(targetSumWays);
    }
//动态规划法
    //假设加法的总和为x,那么减法对应的总和就是sum - x。
    //所以我们要求的是 x - (sum - x) = S 即x = (S + sum) / 2
    //此时问题就转化为,装满容量为x背包,有几种方法。
    //此处还是排列问题 所以递归式为dp[j]+=dp[j-nums[i]];
    public int findTargetSumWays2(int[] nums, int target) {
        int sum=0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
        }
        if(target>sum || (target*-1)>sum){
            return 0;
        }
        if((target+sum)%2==1){
            return 0;
        }
        int tt=(target+sum)/2;
        int[] dp=new int[tt+1];
        dp[0]=1;
        for(int i=0;i<nums.length;i++){
            for(int j=tt;j>=nums[i];j--){
                dp[j]+=dp[j-nums[i]];
            }
        }
        return dp[tt];
    }
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号