Given an integer array nums and an integer k, return true if it is 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 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] <= 104
The frequency of each element is in the range [1, 4].
Solutions
Solution 1: DFS + Pruning
According to the problem description, we need to partition the array \(\textit{nums}\) into \(k\) subsets such that the sum of each subset is equal. Therefore, we first sum all the elements in \(\textit{nums}\). If the total sum cannot be divided by \(k\), it means we cannot partition the array into \(k\) subsets, and we return \(\textit{false}\) early.
If the total sum can be divided by \(k\), let's denote the expected sum of each subset as \(s\). Then, we create an array \(\textit{cur}\) of length \(k\) to represent the current sum of each subset.
We sort the array \(\textit{nums}\) in descending order (to reduce the number of searches), and then start from the first element, trying to add it to each subset in \(\textit{cur}\) one by one. If adding \(\textit{nums}[i]\) to a subset \(\textit{cur}[j]\) makes the subset's sum exceed \(s\), it means it cannot be placed in that subset, and we can skip it. Additionally, if \(\textit{cur}[j]\) is equal to \(\textit{cur}[j - 1]\), it means we have already completed the search for \(\textit{cur}[j - 1]\), and we can skip the current search.
If we can add all elements to \(\textit{cur}\), it means we can partition the array into \(k\) subsets, and we return \(\textit{true}\).
Similar to Solution 1, we first check whether the array \(\textit{nums}\) can be partitioned into \(k\) subsets. If it cannot be divided by \(k\), we directly return \(\textit{false}\).
Let \(s\) be the expected sum of each subset, and let \(\textit{state}\) represent the current partitioning state of the elements. For the \(i\)-th number, if the \(i\)-th bit of \(\textit{state}\) is \(0\), it means the \(i\)-th element has not been partitioned.
Our goal is to form \(k\) subsets with a sum of \(s\) from all elements. Let \(t\) be the current sum of the subset. When the \(i\)-th element is not partitioned:
If \(t + \textit{nums}[i] \gt s\), it means the \(i\)-th element cannot be added to the current subset. Since we sort the array \(\textit{nums}\) in ascending order, all elements from position \(i\) onwards cannot be added to the current subset, and we directly return \(\textit{false}\).
Otherwise, add the \(i\)-th element to the current subset, change the state to \(\textit{state} | 2^i\), and continue searching for unpartitioned elements. Note that if \(t + \textit{nums}[i] = s\), it means we can form a subset with a sum of \(s\). The next step is to reset \(t\) to zero (which can be achieved by \((t + \textit{nums}[i]) \bmod s\)) and continue partitioning the next subset.
To avoid repeated searches, we use an array \(\textit{f}\) of length \(2^n\) to record the search results for each state. The array \(\textit{f}\) has three possible values:
0 indicates that the current state has not been searched yet;
-1: indicates that the current state cannot be partitioned into \(k\) subsets;
1: indicates that the current state can be partitioned into \(k\) subsets.
The time complexity is \(O(n \times 2^n)\), and the space complexity is \(O(2^n)\). Here, \(n\) represents the length of the array \(\textit{nums}\). For each state, we need to traverse the array \(\textit{nums}\), which has a time complexity of \(O(n)\). The total number of states is \(2^n\), so the overall time complexity is \(O(n \times 2^n)\).
We can use dynamic programming to solve this problem.
We define \(f[i]\) to represent whether there exists \(k\) subsets that meet the requirements when the current selected numbers' state is \(i\). Initially, \(f[0] = \text{true}\), and the answer is \(f[2^n - 1]\), where \(n\) is the length of the array \(\textit{nums}\). Additionally, we define \(cur[i]\) to represent the sum of the last subset when the current selected numbers' state is \(i\).
We enumerate the states \(i\) in the range \([0, 2^n]\). For each state \(i\), if \(f[i]\) is \(\text{false}\), we skip it. Otherwise, we enumerate any number \(\textit{nums}[j]\) in the array \(\textit{nums}\). If \(cur[i] + \textit{nums}[j] > s\), we break the enumeration loop because the subsequent numbers are larger and cannot be placed in the current subset. Otherwise, if the \(j\)-th bit of the binary representation of \(i\) is \(0\), it means the current \(\textit{nums}[j]\) has not been selected. We can place it in the current subset, change the state to \(i | 2^j\), update \(cur[i | 2^j] = (cur[i] + \textit{nums}[j]) \bmod s\), and set \(f[i | 2^j] = \text{true}\).
Finally, we return \(f[2^n - 1]\).
The time complexity is \(O(n \times 2^n)\), and the space complexity is \(O(2^n)\). Here, \(n\) represents the length of the array \(\textit{nums}\).