题目:
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 = 4 Output: True Explanation: 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
.思路:
一道稍微有点变种的DFS + backtracking题目。我们首先计算nums数组的总和sum,然后判断k是否介于nums数组的大小之间,以及是否能够整除sum,如果任意一个条件不满足,则返回false。接着在canPartition函数中进行递归搜索。当k == 1时,说明搜索已经完成,返回true;当cur_sum == target的时候,说明我们已经完成了一个partition,所以再从头开始构造另外一个partition(这里有个可以优化的地方:如果cur_sum > target,说明已经超出了sum / k的范围了,可以进行剪枝,直接返回false)。否则,我们就让i从start_index开始往后循环到结束,试图将nums[i]放在当前的桶中。当然当DFS返回false的时候,我们还需要回溯。
代码:
class Solution { public: bool canPartitionKSubsets(vector<int>& nums, int k) { int sum = 0; for (int num : nums) { sum += num; } if (k <= 0 || k > nums.size() || sum % k != 0) { return false; } vector<bool> visited(nums.size(), false); return canPartition(nums, visited, 0, k, 0, sum / k); } private: bool canPartition(vector<int>& nums, vector<bool>& visited, int start_index, int k, int cur_sum, int target) { if (k == 1) { return true; } if (cur_sum == target) { // we have finished one partition return canPartition(nums, visited, 0, k - 1, 0, target); } else if (cur_sum > target) { // optimization return false; } for (int i = start_index; i < nums.size(); ++i) { if(!visited[i]) { visited[i] = true; if (canPartition(nums, visited, i + 1, k, cur_sum + nums[i], target)) { return true; } visited[i] = false; // backtracking } } return false; } };