698. Partition to K Equal Sum Subsets
At a Glance
- Topic: backtracking
- Pattern: DFS / Backtracking
- Difficulty: Medium
- Companies: Amazon, Google, Microsoft, Meta, Bloomberg
- Frequency: Medium
- LeetCode: 698
Problem (one-liner)
Partition nums into exactly k non-empty subsets with equal sum (each subset sums to total/k). Return whether possible.
Recognition Cues
- Target subset sum known if
total % k == 0 - NP-complete flavor — use backtracking with buckets or bitmask memo in optimized variants
- Sort descending to prune faster
Diagram
At-a-glance flow (replace with problem-specific Mermaid as you refine this note). camelCase node IDs; no spaces in IDs.
Loading diagram…
Approaches
- Brute — partition enumeration — infeasible.
- Better — DFS assign each number to one of
kbuckets tracking current sums — backtracking with pruning. - Memoization — bitmask state
(mask, bucketIndex)optional acceleration.
Optimal Solution
Go
import "sort"
func canPartitionKSubsets(nums []int, buckets int) bool {
total := 0
for _, value := range nums {
total += value
}
if total% buckets != 0 {
return false
}
target := total / buckets
sort.Slice(nums, func(left, right int) bool {
return nums[left] > nums[right]
})
bucketSums := make([]int, buckets)
var dfs func(index int) bool
dfs = func(index int) bool {
if index == len(nums) {
return true
}
value := nums[index]
for bucketIndex := 0; bucketIndex < buckets; bucketIndex++ {
if bucketSums[bucketIndex]+value > target {
continue
}
bucketSums[bucketIndex] += value
if dfs(index + 1) {
return true
}
bucketSums[bucketIndex] -= value
if bucketSums[bucketIndex] == 0 {
break
}
}
return false
}
return dfs(0)
}JavaScript
function canPartitionKSubsets(nums, bucketCount) {
const total = nums.reduce((sum, value) => sum + value, 0);
if (total % bucketCount !== 0) {
return false;
}
const target = total / bucketCount;
nums.sort((left, right) => right - left);
const bucketSums = new Array(bucketCount).fill(0);
function dfs(index) {
if (index === nums.length) {
return true;
}
const value = nums[index];
for (let bucketIndex = 0; bucketIndex < bucketCount; bucketIndex += 1) {
if (bucketSums[bucketIndex] + value > target) {
continue;
}
bucketSums[bucketIndex] += value;
if (dfs(index + 1)) {
return true;
}
bucketSums[bucketIndex] -= value;
if (bucketSums[bucketIndex] === 0) {
break;
}
}
return false;
}
return dfs(0);
}Walkthrough
If total % k != 0, immediate false. Else fill buckets greedily with largest-first DFS.
Invariant: Each recursion places nums[index] into some bucket without exceeding target; symmetry pruning skips empty bucket repeats.
Edge Cases
k == 1— always true if sum consistent- Single element equal to
target - Impossible remainder —
total % k != 0
Pitfalls
- Ascending sort — weaker pruning
- Not breaking when bucket empty trial fails — duplicate symmetric work
Similar Problems
- 39. Combination Sum — subset sums to a single target
- 40. Combination Sum II — constrained multiset toward one target
- 416. Partition Equal Subset Sum — k = 2 special case
Variants
- K equal sum subsets with multiset — same backtracking, stronger dedupe.
- Minimize largest bucket sum — becomes different problem (see split array largest sum / binary search on answer).
Mind-Map Tags
#backtracking #bucket-fill #pruning #sort-desc #bitmask-optional
Last updated on
Spotted something unclear or wrong on this page?