Given an integer array nums
and an integer k
, determine if it's possible to divide this array into k
non-empty subsets such that the sum of elements in each subset is equal.
Example 1:
nums = [4, 3, 2, 3, 5, 2, 1], k = 4
Output: true
Explanation: The array can be divided into the following 4 subsets: (5)
, (1, 4)
, (2, 3)
, (2, 3)
, each having a sum of 5.
Example 2:
nums = [1, 2, 3, 4], k = 3
Output: false
Constraints:
1 <= k <= nums.length <= 16
1 <= nums[i] <= 10^4
[1, 4]
Could you implement a function that solves this problem efficiently?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to this problem involves trying every single possible way to divide the numbers into the required number of groups. We explore all combinations to see if any arrangement results in each group having the same sum. Think of it like shuffling cards and dealing them into piles to see if the piles have the same total value.
Here's how the algorithm would work step-by-step:
def can_partition_to_k_equal_sum_subsets_brute_force(
numbers, number_of_subsets
):
total_sum = sum(numbers)
if total_sum % number_of_subsets != 0:
return False
target_sum = total_sum // number_of_subsets
subsets = [0] * number_of_subsets
def can_partition_recursive(index):
if index == len(numbers):
# Check if all subsets have the same sum
return all(subset_sum == target_sum for subset_sum in subsets)
for i in range(number_of_subsets):
# Try adding the current number to each subset
subsets[i] += numbers[index]
if subsets[i] <= target_sum:
if can_partition_recursive(index + 1):
return True
# Backtrack: Undo the addition to explore other possibilities
subsets[i] -= numbers[index]
return False
# Initiate the recursive process
return can_partition_recursive(0)
The core idea is to see if it's even possible to split the numbers into equal sum groups before doing any real work. Then, we try to build these groups one at a time, stopping early if we realize we're on the wrong path.
Here's how the algorithm would work step-by-step:
def canPartitionKSubsets(numbers, k):
total_sum = sum(numbers)
if total_sum % k != 0:
return False
target_sum_for_subset = total_sum // k
number_of_elements = len(numbers)
used_elements = [False] * number_of_elements
def can_form_subset(current_subset_sum, elements_used,
start_index, subsets_formed):
if subsets_formed == k:
return True
if current_subset_sum == target_sum_for_subset:
# Move onto forming the next subset
return can_form_subset(0, elements_used, 0, subsets_formed + 1)
if current_subset_sum > target_sum_for_subset:
return False
for i in range(start_index, number_of_elements):
if not elements_used[i]:
elements_used[i] = True
# Explore using this number in the current subset
if can_form_subset(current_subset_sum + numbers[i],
elements_used, i + 1, subsets_formed):
return True
# Backtrack if including the number didn't work
elements_used[i] = False
return False
# If total_sum % k is 0, target sum is calculated
return can_form_subset(0, used_elements, 0, 0)
Case | How to Handle |
---|---|
Null or empty input array | Return False, as partitioning an empty set is impossible. |
k is zero or negative | Return False, as we cannot partition into a non-positive number of subsets. |
k is greater than the number of elements in the array | Return False, as each subset must have at least one element. |
Sum of array elements is not divisible by k | Return False, as equal sum subsets are impossible if the total sum is not evenly divisible. |
Array contains negative numbers | The problem statement does not specify that all numbers must be non-negative, so the backtracking logic needs to account for negative values, and should return False if the subset target becomes negative. |
Array contains large numbers, leading to integer overflow when calculating the sum | Use a data type with a larger range (e.g., long) to store the sum of array elements. |
All elements are zero | If the total sum is zero and k is less than or equal to n, then a valid partition is possible. |
A single element is greater than the target subset sum | Return False, because no valid partition can exist if one element is already greater than the target subset sum. |