LeetCode698. 划分为k个相等的子集

题目

给定一个整数数组  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

解题思路

  1. 首先可以计算出每个子集的和的值  average =  sum / k;此后就围绕着这个值进行
  2. 之后就是需要组成将nums中的值,组成 7 个 average
  3. 其次明确递归函数的目的与作用   :   将函数的最大值,放入到一个合适的位置
  4. 具体思路随代码

代码

class Solution {
public:
    bool canPartitionKSubsets(vector<int>& nums, int k) {

        int sum = accumulate(nums.begin(), nums.end(), 0);
        
        if(sum % k != 0)  return false;
        
        int average = sum / k;
        
        sort(nums.begin(), nums.end());
        
        if(nums.back() > average)   return false;
        
        while(nums.size() && nums.back() == average)
        {
            nums.pop_back();
            k -= 1;
        }
        //在这之上都只是一些基础的判断准备工作
vector
<int> flag(k, 0); int ret = Partition(flag, nums, average); return ret; } private: bool Partition(vector<int> &flag, vector<int> nums, int average)
  //这里nums必须传值,而flag传引用即可,稍后说明
  //flag长度为k,目的就是flag中的k个值,每个达到average
  //每次将最大的值放入到flag中的一个位置(相加),保证不超过average
{
if(!nums.size()) return true;
     //如果按照要求一个一个放入,最后nums空了,即说明成功,返回true
int max = nums.back(); nums.pop_back();   //弹出最大值 for(auto &c : flag) { if(c + max <= average) { c += max;
          //1,在flag中寻找合适的位置,相加
          //2,相加值小于average即表示有可能
          //3,只是尝试性的加入,但是在函数开头我们是将值弹出的,所以需要值传递nums
if(Partition(flag, nums, average)) return true;
          //nums从大到小逐个递归,如果所有的nums都成功放入flags,返回true
          //如果有失败,则说明这个尝试失败
c
-= max;
          //4,如果失败flag会修改回来,所以使用引用即可 }
if(c == 0) break;
        //这个地方原本值为0结果失败,flag之后的值也为0,没有必要尝试 }
return false;
     //只有递归返回true才说明成功 }; };

 

posted @ 2019-03-20 22:15  一叶而知天下秋  阅读(1280)  评论(0编辑  收藏  举报