一、题目
二、代码
状态压缩
class Solution {
public boolean canPartitionKSubsets(int[] nums, int k) {
if (k == 1) {
return true;
}
int len = nums.length;
Arrays.sort(nums);
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum % k != 0) {
return false;
}
int target = sum / k;
if (nums[len - 1] > target) {
return false;
}
//状态压缩:每个数都能用0表示为不选择,1表示为选择,假设数组的长度为7,那么一共有2 ^ 7种状态
//如果len == 7, size = 1 * pow(2, 7) 或者 转化成二进制位进行左移操作
int size = 1 << len;
//使用dp[i]表示第i(i >= 0 && i <128)种状态能否分为若干个之和为target的数组
int[] dp = new int[size];
Arrays.fill(dp, -1);
dp[0] = 0;
//currentSum[i] i >= 0 && i < 128 意义是将其转化为7位二进制位,0就是选择1就是不选择。currentSum[i]表示选择的数组元素之和
int[] currentSum = new int[size];
for (int i = 0; i < size; i++) {
// 总是基于 dp[i] = true 的前提下进行状态转移
if (dp[i] == -1) {
continue;
}
// 基于当前状态,添加一个数以后
for (int j = 0; j < len; j++) {
if ((i & (1 << j)) != 0) {
continue;
}
//i的第j位变成1
int next = i | (1 << j);
if (dp[next] == 0) {
continue;
}
if ((currentSum[i] % target) + nums[j] <= target) {
currentSum[next] = currentSum[i] + nums[j];
dp[next] = currentSum[next] % target;
} else {
// 由于数组已经排好序,如果 (currentSum[i] % target) + nums[j] > target,剩下的数就没有必要枚举
break;
}
}
}
return dp[size - 1] == 0;
}
}