代码随想录算法训练营第35天|LeetCode 01背包问题 二维、01背包问题 一维、416. 分割等和子集

1. LeetCode 01背包问题 二维

题目链接:https://kamacoder.com/problempage.php?pid=1046
文章链接:https://programmercarl.com/背包理论基础01背包-1.html#算法公开课
视频链接:https://www.bilibili.com/video/BV1cg411g7Y6/

在这里插入图片描述

思路:
01背包问题

  1. 定义dp数组 dp[i][j]表示在0~i物品内任意选择,放入j空间大小的背包中的最大价值
    int[][] dp = new int[M][N+1];
  2. 递推公式
    dp[i][j] =
    Math.max(dp[i-1][j],dp[i-1][j-Integer.valueOf(space[i])]+Integer.valueOf(value[i]))
  3. 初始化
    for (int j=Integer.valueOf(space[0]);j<=N;j++) {
    dp[0][j] = Integer.valueOf(value[0]);
    }
  4. 遍历顺序 先物品再空间

注意:
1️⃣若当前背包的容量都没有当前物品i大的时候,是不放物品i的。那么前i-1个物品能放下的最大价值就是当前情况的最大价值;
2️⃣若当前背包的容量可以放下物品i
那么此时分两种情况:
1、不放物品i
2、放物品i
比较这两种情况下,哪种背包中物品的最大价值最大

import java.util.*;

// 01背包问题
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] firLine = sc.nextLine().split(" ");
        String[] space = sc.nextLine().split(" ");
        String[] value = sc.nextLine().split(" ");
        int M = Integer.valueOf(firLine[0]); // 物品数量
        int N = Integer.valueOf(firLine[1]); // 背包空间
        
        // 1. 定义dp数组 dp[i][j]表示在0~i物品内选择j空间的最大价值
        int[][] dp = new int[M][N+1];
        
        // 2. 递推公式
        // dp[i][j] = Math.max(dp[i-1][j],
        // dp[i-1][j-Integer.valueOf(space[i])]+Integer.valueOf(value[i]))
        
        // 3. 初始化
        for (int j=Integer.valueOf(space[0]);j<=N;j++) {
            dp[0][j] = Integer.valueOf(value[0]);
        }
    
        
        // 4. 遍历顺序 先物品再空间
        for (int i=1;i<M;i++) {
            for (int j=0;j<N+1;j++) {
                if (j < Integer.valueOf(space[i])) {
                    dp[i][j] = dp[i-1][j];
                } else {
                    dp[i][j] = Math.max(dp[i-1][j],
                    dp[i-1][j-Integer.valueOf(space[i])]+Integer.valueOf(value[i]));
                }
            }
        }
        
        System.out.println(dp[M-1][N]);
        
    }
}

2. LeetCode 01背包问题 一维

题目链接:https://kamacoder.com/problempage.php?pid=1046
文章链接:https://programmercarl.com/背包理论基础01背包-2.html#思路
视频链接:https://www.bilibili.com/video/BV1BU4y177kY/

思路:
01背包问题

  1. 确定dp数组的定义
    在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。
  2. 一维dp数组的递推公式
    dp[j]有两个选择:
    (1)不放物品i:取自己dp[j],相当于 二维dp数组中的dp[i-1][j];
    (2)放物品i:取dp[j - weight[i]] + value[i]。
    dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
  3. 一维dp数组如何初始化
    关于初始化,一定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱。dp[0]应该是0,因为背包容量为0所背的物品的最大价值就是0。
    除了下标0的位置,假设物品价值都是大于0的,所以dp数组初始化的时候,都初始为0就可以了。
  4. 一维dp数组遍历顺序
for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }// j>=weight[i],即物品i只能放到weight大于该物品重量的背包中。
}// 归根结底,当前物品只可能放入背包重量大于当前物品重量的背包中
import java.util.*;

// // 01背包问题
// // 二维数组
// public class Main {
//     public static void main(String[] args) {
//         Scanner sc = new Scanner(System.in);
//         String[] firLine = sc.nextLine().split(" ");
//         String[] space = sc.nextLine().split(" ");
//         String[] value = sc.nextLine().split(" ");
//         int M = Integer.valueOf(firLine[0]); // 物品数量
//         int N = Integer.valueOf(firLine[1]); // 背包空间
        
//         // 1. 定义dp数组 dp[i][j]表示在0~i物品内选择j空间的最大价值
//         int[][] dp = new int[M][N+1];
        
//         // 2. 递推公式
//         // dp[i][j] = Math.max(dp[i-1][j],
//         // dp[i-1][j-Integer.valueOf(space[i])]+Integer.valueOf(value[i]))
        
//         // 3. 初始化
//         for (int j=Integer.valueOf(space[0]);j<=N;j++) {
//             dp[0][j] = Integer.valueOf(value[0]);
//         }
    
        
//         // 4. 遍历顺序 先物品再空间
//         for (int i=1;i<M;i++) {
//             for (int j=0;j<N+1;j++) {
//                 if (j < Integer.valueOf(space[i])) {
//                     dp[i][j] = dp[i-1][j];
//                 } else {
//                     dp[i][j] = Math.max(dp[i-1][j],
//                     dp[i-1][j-Integer.valueOf(space[i])]+Integer.valueOf(value[i]));
//                 }
//             }
//         }
        
//         System.out.println(dp[M-1][N]);
        
//     }
// }

// 一维数组

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] firLine = sc.nextLine().split(" ");
        String[] space = sc.nextLine().split(" ");
        String[] value = sc.nextLine().split(" ");
        int M = Integer.valueOf(firLine[0]); // 物品数量
        int N = Integer.valueOf(firLine[1]); // 背包空间
        
        // 1. 定义dp数组 dp[j]表示空间j的背包的最大价值
        int[] dp = new int[N+1];
        
        // 2. 递推公式
        // dp[j] = Math.max(dp[j],dp[j-Integer.valueOf(space[i])]+Integer.valueOf(value[i]))
        // 3. 初始化
    
        
        // 4. 遍历顺序 先物品再空间
        for (int i=0;i<M;i++) {
            for (int j=N;j>=Integer.valueOf(space[i]);j--) {
                dp[j] = Math.max(dp[j],dp[j-Integer.valueOf(space[i])]+Integer.valueOf(value[i]));
            }
        }
        
        System.out.println(dp[N]);
        
    }
}

3. LeetCode 416. 分割等和子集

题目链接:https://leetcode.cn/problems/partition-equal-subset-sum/description/
文章链接:https://programmercarl.com/0416.分割等和子集.html
视频链接:https://www.bilibili.com/video/BV1rt4y1N7jE/

在这里插入图片描述

思路:此题是01背包应用类题。
题目中物品是nums[i],重量是nums[i],价值也是nums[i],背包体积是sum/2。
只有确定了如下四点,才能把01背包问题套到本题上来。
1.背包的体积为sum / 2
2.背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
3.背包如果正好装满,说明找到了总和为 sum / 2 的子集。
4.背包中每一个元素是不可重复放入。

解法:
class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int i=0;i<nums.length;i++) {
            sum += nums[i];
        }
        if (sum%2==1) return false;
        int N = sum/2;

        //1. 定义dp数组 dp[j] 表示 容量j的背包所能获取的最大的物品价值
        // 注意:这里物品的重量=物品的价值。最大的物品价值=最大的物品重量
        int[] dp = new int[N+1];

        //2.递推公式
        //dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);

        //3.初始化
        //4.遍历顺序 先物品再背包
        for (int i=0;i<nums.length;i++) {
            for (int j=N;j>=nums[i];j--) {
                dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);
            }
        }

        return dp[N]==N;
    }
}
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值