leetcode698- Partition to K Equal Sum Subsets- medium
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。简单一点的类似问题是subset问题,问你一个数组里能不能找到一些数加起来是target。那这个问题其实就相当于target = sum / k,然后你找到一个合格的subset再找一下一个,直到你正好凑满k个合格的subset。所以这道题里其实就是难一点点双层出口,别的思路差不多。
递归函数头:private boolean canPartition(int[] nums, boolean[] isUsed, int k, int target, int idx, int crtSum) 。函数意义是在给定的剩余可用的nums下,你最终能不能再凑出k个加起来是target的subset?第一个出口是:当你当前凑到一个合格subset后,你要出去递归下一个只需要再凑k-1个的问题。第二个出口是:当你k减到0也就是凑满的时候,你就是真的可以拍胸脯说这个问题是有解的啦,返回。
细节:1.函数头里的idx是让你不回头加数,因为这个问题不是排列问题,你选的数字135凑到9和选的数字153凑到9是一样的,不要重复搜索了。2.递归的时候还有一层出口的时候要把结果返回去,子函数结尾遍历后都不行要把false返回去。
实现:
class Solution { public boolean canPartitionKSubsets(int[] nums, int k) { if (nums == null || nums.length == 0) { return false; } int sum = 0; for (int i = 0; i < nums.length; i++) { sum += nums[i]; } if (sum % k != 0) { return false; } int target = sum / k; boolean[] isUsed = new boolean[nums.length]; return canPartition(nums, isUsed, k, target, 0, 0); } private boolean canPartition(int[] nums, boolean[] isUsed, int k, int target, int idx, int crtSum) { if (k == 0) { return true; } if (crtSum == target) { return canPartition(nums, isUsed, k - 1, target, 0, 0); } for (int i = idx; i < nums.length; i++) { if (isUsed[i]) { continue; } isUsed[i] = true; if (canPartition(nums, isUsed, k, target, i + 1, crtSum + nums[i])) { return true; } isUsed[i] = false; } return false; } }