0
点赞
收藏
分享

微信扫一扫

698. 划分为k个相等的子集(记忆化搜索+状态压缩)


Problem: 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)等于总和。
示例 2:

输入: nums = [1,2,3,4], k = 3
输出: false


文章目录

  • 思路
  • 解题方法
  • Code


思路

这道题的目标是将给定的整数数组分成 k 个非空子集,使得每个子集的总和都相等。这可以通过深度优先搜索(DFS)来解决,同时使用备忘录(memo)来优化搜索过程。

解题方法

  1. 总和计算:首先计算整数数组的总和,如果总和不能被 k 整除,那么无法分成 k 个总和相等的子集,直接返回 false。
  2. 目标子集和:计算每个子集应该达到的目标和,即总和除以 k。
  3. DFS 搜索:使用深度优先搜索来探索所有可能的子集组合。在搜索的过程中,记录哪些元素已经被选择,以及当前子集的总和。
  4. 备忘录(memo):为了避免重复计算,使用备忘录(memo)来存储已经计算过的状态。备忘录的键是一个整数 vis,它用位掩码的方式表示哪些元素已经被选择,以及当前的子集总和。这样可以避免在相同状态下的重复搜索。

最终返回 dfs 函数的结果,判断是否可以成功将数组分成 k 个总和相等的子集。

Code

class Solution {
public:
    // int currentSum = 0;
    // 使用 备忘录
    unordered_map<int,bool> memo ; 
    bool dfs(vector<int>& nums,int & vis,int target,int start,int k,int currentSum){
        if(k == 0) return true  ; // 分组完成
        if(currentSum == target) {
            // 继续分下一个组
            // currentSum = 0 ;
            bool res = dfs(nums,vis,target,0,k-1,0) ; 
            memo[vis] = res ; 

            return res ;  
        }
        if(memo.count(vis)) {
            return memo[vis] ; 
        }
         
        for(int i = start ; i<nums.size() ;i++) {
            
            if( (vis >> i) & 1 == 1 ) {
                // 判断第 i位是否是1 ,即有没有选择第i个Num
                continue ; 
            }

            if( currentSum +nums[i] <= target) {
                vis |= 1<<i ;// 标记        
                if(dfs(nums,vis,target,i+1,k,currentSum+nums[i])) return true ;  
                vis ^= 1<<i ;// 标记
            }
        }
        return false ; 

    }
    bool canPartitionKSubsets(vector<int>& nums, int k) {
        int n = nums.size() ; 
        int sum = 0 ; 
        sort(nums.begin() ,nums.end()) ;

        for(int i = 0; i <n ; i++ ) {
            sum+=nums[i] ; 
        }
        if(sum %k !=0) return false ; 
        int target = sum/k ; 

        // vector<bool> vis(nums.size(),false ) ; 
        int vis = 0 ; // 用来记录每个元素是否被 选择过
        // 一开始是0 对应二进制是 000.0000表示还没选择
        return dfs(nums,vis,target,0,k,0);

    }
};


举报

相关推荐

0 条评论