Given an integer array nums
and an integer k
, determine whether it is possible to divide this array into k
non-empty subsets such that the sum of elements in each subset is the same.
Details:
true
if such a division is possible and false
otherwise.nums
contains positive integers.k
is a positive integer.nums
must belong to exactly one subset.Example 1:
Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
Output: true
Explanation: It is possible to divide it into 4 subsets (5), (1, 4), (2, 3), (2, 3) with equal sums.
Example 2:
Input: nums = [1, 2, 3, 4], k = 3
Output: false
Constraints:
1 <= k <= nums.length <= 16
1 <= nums[i] <= 10^4
[1, 4]
.A brute-force approach would involve generating all possible subsets of the input array and checking if we can form k
subsets with equal sums. This method is highly inefficient due to the exponential number of possible subsets.
A more efficient approach uses dynamic programming and bit masking to track which elements have been used in subsets. The main idea is as follows:
nums
. If the sum is not divisible by k
, we cannot divide the array into k
equal sum subsets, so return false
.k
to get the target sum for each subset.nums
are already used in subsets. The value at each index is a boolean: true
if it's possible to form subsets with the given mask and target sum, false
otherwise.totalSum
and check if totalSum % k == 0
. If not, return false
.targetSum = totalSum / k
.dp
array of size 2^n
, initialized to false
. dp[0] = true
because an empty subset is always valid.0
to 2^n - 1
:
dp[mask]
is true
, iterate through each element in nums
:
i
-th element is not in the current mask (i.e., (mask & (1 << i)) == 0
):
newMask = mask | (1 << i)
.newMask
does not exceed targetSum
, set dp[newMask] = true
.dp[(1 << n) - 1]
will be true
if it's possible to divide the array into k
subsets with equal sums. Return this value.k
is non-positive, handle the edge case appropriately. Should return true
if the array is empty and k
is 1, false
otherwise.class Solution:
def canPartitionKSubsets(self, nums: List[int], k: int) -> bool:
total_sum = sum(nums)
if total_sum % k != 0:
return False
target_sum = total_sum // k
n = len(nums)
dp = [False] * (1 << n)
dp[0] = True
for mask in range(1 << n):
if not dp[mask]:
continue
for i in range(n):
if not (mask & (1 << i)):
new_mask = mask | (1 << i)
subset_sum = 0
for j in range(n):
if (new_mask & (1 << j)):
subset_sum += nums[j]
temp_sum = 0
temp_mask = new_mask
for j in range(n):
if (mask & (1 << j)):
temp_sum += nums[j]
subset_sum_diff = subset_sum - temp_sum
if subset_sum_diff <= target_sum:
temp_sum_new_mask = 0
bin_num = bin(new_mask)[2:].zfill(n)
for bit_index in range(len(bin_num)):
if bin_num[bit_index] == '1':
temp_sum_new_mask += nums[bit_index]
if temp_sum_new_mask % target_sum == 0:
dp[new_mask] = True
elif temp_sum_new_mask < target_sum:
dp[new_mask] = True
else:
dp[new_mask] = False
return dp[(1 << n) - 1]