Day31 | 416分割等和子集&1049最后一块石头的重量 II&494目标和&474一和零

79 阅读2分钟

分割等和子集 LeetCode 416

题目链接:[LeetCode 416 - 中等]

思路

解决01背包问题:

①确定dp数组:为容量为target的背包中,装入物品的价值

②确定遍历顺序:由于使用的是一维数组,因此采用的是先遍历物品,后倒序遍历背包。

动态规划:

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for(int num:nums){
            sum+=num;
        }
        if(sum%2==1)return false;
        int target = sum/2;
        int[] dp = new int[target+1];
        for(int i=0;i<nums.length;i++){
            for(int j=target;j>=nums[i];j--){
                dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]);
            }
            if(dp[target]==target)return true;
        }
        return dp[target]==target;
    }
}

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

题目链接:[LeetCode 1049 - 中等]

思路

解决01背包问题:

①将石头相撞问题转化为最后石头的最小重量:因此计算石头的重量,然后整体/2即为背包的大小

②dp数组的意义:背包大小为target的情况下,可以装下的石头的最大重量

③遍历方式:先遍历物品,然后后序遍历背包

⑤题解的答案:一堆石头的大小为dp[target],另一堆石头的大小为sum - dp[target],因此他们相撞之后得到的结果为:sum - 2*dp[target]

动态规划:

class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum=0;
        for(int stone:stones){
            sum+=stone;
        }
        int target=sum/2;
        int[] dp = new int[target+1];
        for(int i=0;i<stones.length;i++){
            for(int j=target;j>=stones[i];j--){
                dp[j]=Math.max(dp[j],dp[j-stones[i]]+stones[i]);
            }
        }
        return sum - 2*dp[target];
    }
}

目标和 LeetCode 494

题目链接:[LeetCode 494 - 中等]

思路

01背包问题:

①如何敲定背包大小:bagSize = (target+sum)/2;(很巧妙)

②确定dp数组:int[] dp = new int[bagSize+1];????

③初始化dp数组:dp[0]=1; -> sum+target=0,所以dp[0]=1

④确定遍历顺序:先遍历物品,后倒序遍历背包

动态规划:

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum=0;
        for(int num:nums){
            sum+=num;
        }
        if(Math.abs(target)>sum)return 0;
        if((target+sum)%2==1)return 0;
        int bagSize = (target+sum)/2;
        int[] dp = new int[bagSize+1];
        dp[0]=1;
        for(int i=0;i<nums.length;i++){
            for(int j=bagSize;j>=nums[i];j--){
                dp[j]+=dp[j-nums[i]];
            }
        }
        return dp[bagSize];
    }
}

一和零 LeetCode 474

题目链接:[LeetCode 474 - 中等]

思路

01背包问题: ①确定dp数组:二维数组,分别为0的个数和1的个数

②确定遍历顺序:先遍历0的个数,倒序遍历,再遍历1的个数,倒序遍历

③条件:dp[i][j]=Math.max(dp[i][j],dp[i-zeroNum][j-oneNum]+1);

动态规划:

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m+1][n+1];
        int oneNum,zeroNum;
        for(String str:strs){
            oneNum=0;
            zeroNum=0;
            for(char ch:str.toCharArray()){
                if(ch=='0'){
                    zeroNum++;
                }else{
                    oneNum++;
                }
            }
            for(int i=m;i>=zeroNum;i--){
                for(int j=n;j>=oneNum;j--){
                    dp[i][j]=Math.max(dp[i][j],dp[i-zeroNum][j-oneNum]+1);
                }
            }
        }
        return dp[m][n];
    }
}