leetcode 416 && 698. 分割等和子集 medium

leetcode 416. 分割等和子集   medium          

题目描述:

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

注意:

每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:

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

输出: true

解释: 数组可以分割成 [1, 5, 5] 和 [11].
 

示例 2:

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

输出: false

解释: 数组不能分割成两个元素和相等的子集.

解题思路:

因为这是要求分割成两个相等的子集,并且所有元素都是正数,所以我们只要求有没有方案使得容量恰为数组一半和Ok了。

01背包,求是否存在容量为数组一半和的方案,所以初始化的时候注意除了dp【0】是true,其他都是false,就ojkb了

代码:

//
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        //01背包,求是否存在容量恰为数组一半和的方案
        
        
        if(nums.size()<2)
            return false;
        
        int sum=0;
        for(int i:nums)
            sum += i;
        
        if(sum & 1)  // 奇数 impossible
            return false;
        sum >>= 1;
        
        vector<bool> dp(1+sum,false);
        dp[0]=true;
        for(int i:nums){
            if(dp[sum]==true) return true; // 中间可以加个速
            for(int j=sum;j>=i;--j) //01背包 容量从大到小遍历
                dp[j]=dp[j] || dp[j-i];
        }
        return dp[sum];
    }
};

leetcode 698. 划分为k个相等的子集   medium          

题目描述:

给定一个整数数组  nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。

示例 1:

输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
输出: True
说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
 

注意:

1 <= k <= len(nums) <= 16
0 < nums[i] < 10000

解题思路:

用回溯法(另外这是求集合,所以要有start开始位置这个变量,因为对于数组【1,2,3】 来说,【1,2】和【2,1】是一样的)

剪枝:

1) 首先判断sum是否能整除k,不能整除的话直接返回false。

2) 因为数组里全部是正数,如果这一轮的和大于target了,直接返回false

3) 

代码:

class Solution {
public:
    bool canPartitionKSubsets(vector<int>& nums, int k) {
        int sum = 0;
        for (auto &i: nums)
            sum += i;
        
        if (sum % k)
            return false;
        
        sum /= k;
        vector<bool> visited(nums.size(), false);

        return dfs(nums, visited, sum, 0, k, 0);

    }


    bool dfs(vector<int> &nums, vector<bool> &visited, int target, int cur_sum, int k, int start){
        if (k == 0)
            return true;
        if (cur_sum > target)
            return false;

        if (cur_sum == target)
            return dfs(nums, visited, target, 0, k-1, 0);

        for (int i = start; i < nums.size(); i++){
            if (visited[i])
                continue;
            visited[i] = true;
            if (dfs(nums, visited, target, cur_sum+nums[i], k, i+1))
                return true;
            visited[i] = false;
        }

        return false;

    }

};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值