数据结构和算法01 背包的应用

Posted Linux猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构和算法01 背包的应用相关的知识,希望对你有一定的参考价值。


🎈 作者:Linux猿

🎈 简介:CSDN博客专家🏆,华为云享专家🏆,Linux、C/C++、云计算、物联网、面试、刷题、算法尽管咨询我,关注我,有问题私聊!

🎈 关注专栏: 数据结构和算法成神路【精讲】优质好文持续更新中……🚀🚀🚀

🎈 欢迎小伙伴们点赞👍、收藏⭐、留言💬


目录

🍓一、题目描述

🍓二、测试样例

🥝2.1 样例 1

🥝2.2 样例 2

🍓三、算法思路

🍓四、代码实现

🍓五、复杂度分析

🥝5.1 时间复杂度

🥝5.2 空间复杂度

🍓六、总结


背包问题在算法中经常用到,尤其是01 背包,下面就来看一下 01 背包的应用。

🍓一、题目描述

给定一个只包含正整数的非空数组 nums 。请判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

提示:

1 <= nums.length <= 200

1 <= nums[i] <= 100

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

🍓二、测试样例

🥝2.1 样例 1

输入:nums = [1,5,11,5]

输出:true

说明:数组可以分割成 [1, 5, 5] 和 [11] ,两者之和都为 11。

🥝2.2 样例 2

输入:nums = [1,2,3,5]

输出:false

说明:数组之和为 11,显然不能分割成两个元素和相等的子集。

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

🍓三、算法思路

本题可以将题意简化为:

判断正整数数组 nums 是否存在一个子集,这个子集的和为 nums 数组中所有值和的一半。

题意转化后就好解题了,就是在 nums 中挑选一些数字,这些数字之和正好组成一个给定的数,很明显是一个背包问题,因为物品(nums 中的数字)不能重复选择,所以是一个 背包问题

01 背包问题可以 关注专栏 数据结构和算法成神路【精讲】

注意:这里要求背包正好装满(挑选的子集中的数字之和正好为 nums 数组所有数和的一半)。

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

🍓四、代码实现

#include <iostream>
#include <vector>
#include <string.h>
using namespace std;

class Solution 
public:
    bool canPartition(vector<int>& nums) 
        int sum = 0;
        //1. 计算 nums 中所有数字的和
        for(int i = 0; i < (int)nums.size(); ++i) 
            sum += nums[i];
        
        // sum 如果为奇数,必定不能分割
        if(sum%2) return false;
        sum /= 2;

        //使用 bool 类型即可
        bool dp[sum + 5];
        memset(dp, false, sizeof(dp));
        dp[0] = true;
        // 01 背包
        for(int i = 0; i < (int)nums.size(); ++i) 
            for(int j = sum; j >= nums[i]; --j) 
                if(dp[j - nums[i]]) 
                    dp[j] = true;
                
            
        
        return dp[sum];
    
;

int main()

    //test
    int a[] = 1, 5, 11, 5;
    vector<int>nums(a, a + 4);

    //int b[] = 2, 2, 3, 5;
    //vector<int>nums(b, b + 4);

    Solution obj;
    cout<<obj.canPartition(nums)<<endl;
    return 0;

其中,sum 为计算 nums 数组中的所有数字之和。第一个 for 循环计算 nums 数组中的所有数字之和。

接下来的两层 for 循环是 01 背包算法,遍历数组判断容量为 sum/2 的背包是否能够正好装满。

通过后的截图如下所示。 

图1 通过截图

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

🍓五、复杂度分析

🥝5.1 时间复杂度

时间复杂度为:O(n*m),其中,n 为 nums 数组长度,m 为 nums 数组值总和的一半。在上述代码中,时间复杂度主要在01 背包(两层 for 循环)处,所以总的时间复杂度为 O(n * m)。

🥝5.2 空间复杂度

空间复杂度:O(m),在上述算法中,使用到了一个 dp 数组记录背包的容量,所以空间复杂度为 O(m)。

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

🍓六、总结

本题需要在理解题意的基础上,转化为 01 背包算法解决。


🎈 感觉有帮助记得「一键三连支持下哦!有问题可在评论区留言💬,感谢大家的一路支持!🤞猿哥将持续输出「优质文章回馈大家!🤞🌹🌹🌹🌹🌹🌹🤞


以上是关于数据结构和算法01 背包的应用的主要内容,如果未能解决你的问题,请参考以下文章

数据结构和算法完全背包的应用

数据结构和算法完全背包的应用

01背包

二进制枚举阶乘之和

算法刷题总结

算法刷题总结