Leetcode 698. 划分为k个相等的子集(中等) 回溯算法=集合划分
题目:
给你输入一个数组 nums
和一个正整数 k
,请你判断 nums
是否能够被平分为元素和相同的 k
个子集。
思路:
我们切换到这 n
个数字的视角,每个数字都要选择进入到 k
个桶中的某一个。
使用递归,每次选择一个数,然后遍历桶,看将nums[index]放入哪个桶中可以得到正常结果。如果都不行,则证明不能均分。
如果我们让尽可能多的情况命中剪枝的那个 if 分支,就可以减少递归调用的次数,一定程度上减少时间复杂度。
如何尽可能多的命中这个 if 分支呢?要知道我们的 index
参数是从 0 开始递增的,也就是递归地从 0 开始遍历 nums
数组。
如果我们提前对 nums
数组排序,把大的数字排在前面,那么大的数字会先被分配到 bucket
中,对于之后的数字,bucket[i] + nums[index]
会更大,更容易触发剪枝的 if 条件。
class Solution { public: bool canPartitionKSubsets(vector<int>& nums, int k) { int n=nums.size(); int sum=0; for(int i=0;i<n;++i){ sum+=nums[i]; } // 排除一些基本情况 if(n<k||sum%k!=0) return false; // 理论上每个桶(集合)中数字的和 int target=sum/k; // k 个桶(集合),记录每个桶装的数字之和 vector<int> bucket(k); sort(nums.begin(),nums.end(),[](int a,int b){ return a>b; }); // 穷举,看看 nums 是否能划分成 k 个和为 target 的子集 return backtrack(nums,bucket,0,target); } bool backtrack(vector<int>& nums,vector<int>& bucket, int index, int target) { if(index==nums.size()){ // 检查所有桶的数字之和是否都是 target for(int i=0;i<bucket.size();++i){ if(bucket[i]!=target){ return false; } } // nums 成功平分成 k 个子集 return true; } // 穷举 nums[index] 可能装入的桶 for(int i=0;i<bucket.size();++i){ // 剪枝,桶装装满了 if(bucket[i]+nums[index]>target){ continue; } // 将 nums[index] 装入 bucket[i] bucket[i]+=nums[index]; // 递归穷举下一个数字的选择 if(backtrack(nums,bucket,index+1,target)){ return true; } // 撤销选择 bucket[i]-=nums[index]; } // nums[index] 装入哪个桶都不行 return false; } };
联系方式:emhhbmdfbGlhbmcxOTkxQDEyNi5jb20=
分类:
leetcode
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库