最小不兼容性
难度:
标签:
题目描述
代码结果
运行时间: 57 ms, 内存: 16.0 MB
/*
题目思路:
1. 计算nums的长度,如果不能被k整除,直接返回-1。
2. 使用回溯法尝试将数组划分为k个子集。
3. 确保每个子集中没有重复元素。
4. 计算每个子集的最大值和最小值的差,并累加得到不兼容性和。
5. 返回最小的不兼容性和。
*/
import java.util.*;
import java.util.stream.IntStream;
public class Solution {
public int minimumIncompatibility(int[] nums, int k) {
int n = nums.length;
if (n % k != 0) return -1;
int subsetSize = n / k;
Arrays.sort(nums);
int[] dp = new int[1 << n];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
IntStream.range(0, 1 << n).forEach(mask -> {
if (Integer.bitCount(mask) % subsetSize == 0) {
IntStream.range(0, n).filter(i -> (mask & (1 << i)) == 0).forEach(i -> {
int nextMask = mask | (1 << i);
int minVal = nums[i], maxVal = nums[i];
for (int j = i + 1; j < n; j++) {
if ((mask & (1 << j)) == 0 && nums[j] != nums[i]) {
nextMask |= (1 << j);
maxVal = nums[j];
}
}
dp[nextMask] = Math.min(dp[nextMask], dp[mask] + maxVal - minVal);
});
}
});
return dp[(1 << n) - 1] == Integer.MAX_VALUE ? -1 : dp[(1 << n) - 1];
}
}
解释
方法:
首先检查是否有任何数字出现次数超过k次,如果有,直接返回-1,因为无法形成k个不包含相同元素的子集。之后通过深度优先搜索(DFS)尝试形成所有可能的子集,并计算不兼容性的总和。使用一个整数的位表示法来跟踪哪些元素已被选择。基于位运算的技巧,例如left.bit_count()和left & -left,用来控制和优化搜索过程。如果当前已组成的子集大小达到应有的大小,则尝试开始新的子集。如果找到一个可行的分配方式,那么更新最小不兼容性。这个算法依赖于位运算和回溯来遍历所有可能的子集组合。
时间复杂度:
O(2^n)
空间复杂度:
O(n)
代码细节讲解
🦆
在算法中,为什么选择使用深度优先搜索(DFS)而不是动态规划或其他算法来解决这个问题?
▷🦆
算法实现中提到使用位运算来跟踪元素选择状态,请问这种方法相比传统的数组或集合有什么优势和劣势?
▷🦆
题解中提到,如果一个元素的出现次数超过k次就直接返回-1。这种情况下,是否存在更优的预处理方法来减少不必要的计算?
▷