leetcode:698-划分为k个相等的子集

简介: leetcode:698-划分为k个相等的子集

题目

题目链接

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

示例 1:

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

解题

方法一:回溯

参考链接

这道题的其实和之前的也不太一样,名字中有子集,其实又不是子集问题。不是找出所有情况。另外这个可以说是一种组合问题,但是不是找到所有的组合。

核心是:每次找到一组和,后重头开始遍历,而不是回溯!使用used记录是否使用过,这里的used是全局的。

leetcode-47:全排列 II中的used是针对每个path的,而此题used是针对整个结果的。

当找到的一组和,不满足的时候才使用的是回溯

其实,想简单点,就是每次找到一组和=target的时候,就重新开始找下一组,利用used作为mask,把遍历过的就不再使用了。

class Solution {
public:
    bool backtracing(vector<int>& nums,int k,int target,int sum,int startIndex,vector<bool>& used){
        if(k==0) return true;
        if(sum==target){
            return backtracing(nums,k-1,target,0,0,used);
        }
        for(int i=startIndex;i<nums.size();i++){
            if(!used[i]&&sum+nums[i]<=target){
                used[i]=true;
                if(backtracing(nums,k,target,sum+nums[i],i+1,used)) return true;
                used[i]=false;
            }
        }
        return false;
    }
    bool canPartitionKSubsets(vector<int>& nums, int k) {
        vector<bool> used(nums.size());
        int sum=accumulate(nums.begin(),nums.end(),0);
        if(sum%k!=0) return false;
        int target=sum/k;
        for(int num:nums){//新添加的
            if(num>target) return false;
        }
        return backtracing(nums,k,target,0,0,used);
    }
};

当然for循环的第一句sum+nums[i]<=target是剪枝

当然也可以剪枝换个地方,比如这样剪枝

if(sum==target){
            return backtracing(nums,k-1,target,0,0,used);
        }
        else if(sum>target) return false;

后续力扣对测试样例了,如果不添加这行,会导致超时。

for(int num:nums){//新添加的
    if(num>target) return false;
 }

java

//i=startIndex只是为了提速,否则会超时

class Solution {
    boolean dfs(int[] nums,boolean[] used,int startIndex,int sum,int target,int k){
        if(k==0) return true;
        if(sum==target){
            return dfs(nums,used,0,0,target,k-1);
        }
        for(int i=startIndex;i<nums.length;i++){
            if(used[i]==true||sum+nums[i]>target) continue;
            used[i]=true;
            if(dfs(nums,used,i+1,sum+nums[i],target,k)) return true;
            used[i]=false;
        }
        return false;
    }
    public boolean canPartitionKSubsets(int[] nums, int k) {
        int sum=0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
        }
        if(sum%k!=0) return false;
        int target=sum/k;
        boolean[] used=new boolean[nums.length];
        for(int num:nums){
            if(num>target) return false;
        }
        return dfs(nums,used,0,0,target,k);
    }
}


相关文章
|
4月前
|
Go
golang力扣leetcode 416.分割等和子集
golang力扣leetcode 416.分割等和子集
24 0
|
4月前
代码随想录 Day35 动态规划04 01背包问题和完全背包问题 LeetCode T416 分割等和子集
代码随想录 Day35 动态规划04 01背包问题和完全背包问题 LeetCode T416 分割等和子集
24 0
|
4月前
【Leetcode 78】子集 —— 回溯法
回溯法解题步骤:1. 针对所给问题,定义问题的解空间;2. 确定易于搜索的解空间结构;3. 以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索
|
4月前
|
Go
golang力扣leetcode 2044.统计按位或能得到最大值的子集数目
golang力扣leetcode 2044.统计按位或能得到最大值的子集数目
19 0
|
4月前
|
Go
golang力扣leetcode 90.子集II
golang力扣leetcode 90.子集II
16 1
|
4月前
|
Go
golang力扣leetcode 78.子集
golang力扣leetcode 78.子集
13 0
|
5月前
六六力扣刷题回溯之子集2
六六力扣刷题回溯之子集2
17 0
|
5月前
|
算法
六六力扣刷题回溯之子集
六六力扣刷题回溯之子集
24 0
|
6月前
|
算法
代码随想录算法训练营第四十一天 | LeetCode 416. 分割等和子集
代码随想录算法训练营第四十一天 | LeetCode 416. 分割等和子集
33 1
代码随想录算法训练营第四十一天 | LeetCode 416. 分割等和子集
|
6月前
|
算法
代码随想录算法训练营第二十七天 | LeetCode 93. 复原 IP 地址、78. 子集、90. 子集 II
代码随想录算法训练营第二十七天 | LeetCode 93. 复原 IP 地址、78. 子集、90. 子集 II
34 0

热门文章

最新文章