Leetcode 698. Partition to K Equal Sum Subsets
Given an array of integers nums
and a positive integer k
, return true
if it is possible to divide this array into k
non-empty subsets whose sums are all equal. Otherwise, return false
.
k
subsets of equal sum?
false
.nums
can be up to 16, and the value of each integer can be up to 10,000. The value of k
can also vary but typically will be less than or equal to 16 due to constraints.To solve this problem, we can employ a backtracking approach with memoization to efficiently check each possibility by recursively trying to partition the elements into k
equal sum subsets. Here is a step-by-step strategy:
Calculate the Total Sum: First, compute the sum of all elements in nums
. If this total sum is not divisible by k
, return false
immediately as it can’t be partitioned equally.
Determine Each Subset Sum: If divisible, the target sum for each subset will be total_sum / k
.
Sort and Backtrack: Sort the array in descending order to optimize the backtracking process by trying out larger numbers first, which can reduce the number of recursive calls. Use a recursive function to try partitioning the array into k
groups, ensuring each group’s sum equals the target sum.
Use a State Array for Subsets: Maintain an array to track the current sum of each subset and ensure the total sum equals the target for each subset.
import java.util.Arrays;
public class Solution {
public boolean canPartitionKSubsets(int[] nums, int k) {
int totalSum = Arrays.stream(nums).sum();
if (totalSum % k != 0) {
return false;
}
int targetSum = totalSum / k;
Arrays.sort(nums);
int n = nums.length;
// Early termination: if the largest number is bigger than target sum
if (nums[n - 1] > targetSum) {
return false;
}
int[] subsets = new int[k];
Arrays.fill(subsets, targetSum);
return canPartition(0, nums, subsets);
}
private boolean canPartition(int index, int[] nums, int[] subsets) {
// If index reaches the last position, all items are considered
if (index == nums.length) {
for (int sum : subsets) {
if (sum != 0) {
return false;
}
}
return true;
}
int selectedNum = nums[index];
for (int i = 0; i < subsets.length; i++) {
if (subsets[i] >= selectedNum) {
subsets[i] -= selectedNum;
if (canPartition(index + 1, nums, subsets)) {
return true;
}
subsets[i] += selectedNum; // backtrack
}
// Optimization: If one subset is unable to take the current nums[index] fully, no other allowed subsets will also be able to.
if (subsets[i] == targetSum) {
break;
}
}
return false;
}
}
The time complexity is approximately (O(k^n)), where (n) is the length of the array, and (k) is the number of subsets because in the worst-case scenario, all possible partitions will be attempted. However, with the optimizations and pruning (like sorting and early termination), the actual number of recursive calls can be significantly reduced in practice.
Got blindsided by a question you didn’t expect?
Spend too much time studying?
Or simply don’t have the time to go over all 3000 questions?