【第十三周】698. Partition to K Equal Sum Subsets

来源:互联网 发布:九九乘法口诀java运算 编辑:程序博客网 时间:2024/06/06 11:36

原题

Given an array of integers nums and a positive integer k, find whether it's possible to divide this array into k non-empty subsets whose sums are all equal.Example 1:Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4Output: TrueExplanation: It's possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums.Note:1 <= k <= len(nums) <= 16.0 < nums[i] < 10000.

LeetCode地址:https://leetcode.com/problems/partition-to-k-equal-sum-subsets/description/

解题思路

题目大意:
给定一个数组与一个参数k,求是否能将数组分成k个和相等的非空子集。

很明显我们可以尝试用递归来解决问题:每一层挑选一个数加入子集;通过一层层的递归调用,我们找出所有可能的组合,去寻找符合要求的组合。
程序的开始部分肯定是各种情况检查:k<=1的情况、数组的和是否能被k整除的情况…然后才是递归求解的步骤。
现在的关键点是,如何具体地设计递归方程呢?目标状态是将所有的数全部放到k个子集中,并且子集的和相等;根据这一要求,我们可以定义k个“set”,每选择一个合适的数,首先填满第一个“set”,如果第一个set已满就填到第二个…依次填到最后一个。同时也需要一个visit数组来记录已经被选择过的数。
算法的时间复杂度:O(k*n^2), n为数组的size。

代码

class Solution {public:    bool canPartitionKSubsets(vector<int>& nums, int k) {        int size = nums.size();        if (k == 1)             return true;        if (k > size)             return false;        int sum = 0;        for (int i : nums)             sum += i;        if (sum % k != 0)             return false;        int subset_sum[k];        bool visited[size];        for (int i = 0; i < k; i++)            subset_sum[i] = 0;        for (int i = 0; i < size; i++)            visited[i] = false;        return partition(nums, k, sum/k, subset_sum, visited, 0, 0);    }    /* nums:原数组    // k: 子集数    // sum: 每个子集的目标和    // subset_sum: 子集的当前和    // visited: 访问列表,保存nums里每个数是否被选择    // curSet: 表示当前正在填充的子集序号    // curPos:表示当前从nums选择填充数的起始位置    */    bool partition(vector<int>& nums, int k, int sum, int subset_sum[],                   bool visited[], int curSet, int curPos) {        if (subset_sum[curSet] == sum) {            if (curSet == k - 2) return true;            return partition(nums, k, sum, subset_sum, visited, curSet+1, 0);        }        for (int i = curPos; i < nums.size(); i++) {            if (visited[i]) continue;            int x = subset_sum[curSet] + nums[i];            if (x > sum) continue;            subset_sum[curSet] += nums[i];            visited[i] = true;            bool flag = partition(nums, k, sum, subset_sum, visited, curSet, i+1);            if (flag) return true;            subset_sum[curSet] -= nums[i];            visited[i] = false;        }        return false;    }};

总结

1、递归方程设计