class Solution {
public:
int minimumIncompatibility(vector<int>& nums, int k) {
}
};
1681. 最小不兼容性
给你一个整数数组 nums
和一个整数 k
。你需要将这个数组划分到 k
个相同大小的子集中,使得同一个子集里面没有两个相同的元素。
一个子集的 不兼容性 是该子集里面最大值和最小值的差。
请你返回将数组分成 k
个子集后,各子集 不兼容性 的 和 的 最小值 ,如果无法分成分成 k
个子集,返回 -1
。
子集的定义是数组中一些数字的集合,对数字顺序没有要求。
示例 1:
输入:nums = [1,2,1,4], k = 2 输出:4 解释:最优的分配是 [1,2] 和 [1,4] 。 不兼容性和为 (2-1) + (4-1) = 4 。 注意到 [1,1] 和 [2,4] 可以得到更小的和,但是第一个集合有 2 个相同的元素,所以不可行。
示例 2:
输入:nums = [6,3,8,1,3,1,2,2], k = 4 输出:6 解释:最优的子集分配为 [1,2],[2,3],[6,8] 和 [1,3] 。 不兼容性和为 (2-1) + (3-2) + (8-6) + (3-1) = 6 。
示例 3:
输入:nums = [5,3,3,6,3,3], k = 3 输出:-1 解释:没办法将这些数字分配到 3 个子集且满足每个子集里没有相同数字。
提示:
1 <= k <= nums.length <= 16
nums.length
能被 k
整除。1 <= nums[i] <= nums.length
原站题解
javascript 解法, 执行用时: 592 ms, 内存消耗: 50.7 MB, 提交时间: 2023-06-28 09:37:16
/** * @param {number[]} nums * @param {number} k * @return {number} */ var minimumIncompatibility = function(nums, k) { const n = nums.length, group = n / k, inf = Infinity; const dp = new Array(1 << n).fill(inf); dp[0] = 0; const values = new Map(); for (let mask = 1; mask < (1 << n); mask++) { if (countOnes(mask) !== group) { continue; } let mn = 20, mx = 0; const cur = new Set(); for (let i = 0; i < n; i++) { if ((mask & (1 << i)) > 0) { if (cur.has(nums[i])) { break; } cur.add(nums[i]); mn = Math.min(mn, nums[i]); mx = Math.max(mx, nums[i]); } } if (cur.size == group) { values.set(mask, mx - mn); } } for (let mask = 0; mask < (1 << n); mask++) { if (dp[mask] == inf) { continue; } const seen = new Map(); for (let i = 0; i < n; i++) { if ((mask & (1 << i)) == 0) { seen.set(nums[i], i); } } if (seen.size < group) { continue; } let sub = 0; for (let v of seen.values()) { sub |= (1 << v); } let nxt = sub; while (nxt > 0) { if (values.has(nxt)) { dp[mask | nxt] = Math.min(dp[mask | nxt], dp[mask] + values.get(nxt)); } nxt = (nxt - 1) & sub; } } return (dp[(1 << n) - 1] < inf) ? dp[(1 << n) - 1] : -1; } function countOnes(n) { let count = 0; while (n > 0) { count++; n &= n - 1; } return count; }
java 解法, 执行用时: 21 ms, 内存消耗: 53.5 MB, 提交时间: 2023-06-28 09:36:20
class Solution { int len, n; int[][] memo; int[] nums; int inf = (int)1e9 + 7; public int minimumIncompatibility(int[] nums, int k) { n = nums.length; len = n / k; this.nums = nums; int[] count = new int[n + 1]; for(int e : nums) ++count[e]; for(int e : count) if(e > k) return -1; int m = 1 << n; memo = new int[m - 1][n]; for(int i = 0; i < m - 1; ++i) Arrays.fill(memo[i], -1); Arrays.sort(nums); return dfs(m - 2, 0); } public int dfs(int left, int pre) { if(left == 0) return 0; if(memo[left][pre] > -1) return memo[left][pre]; //创建一个新的组 if(Integer.bitCount(left) % len == 0){ int lowbit = left & -left; return dfs(left ^ lowbit, 32 - Integer.numberOfLeadingZeros(lowbit) - 1); } int res = inf; int last = nums[pre]; for(int i = pre + 1; i < n; ++i) //枚举本组的下一个数 if((left >> i & 1) > 0 && nums[i] != last){ //判断重复数字 last = nums[i]; res = min(res, last - nums[pre] + dfs( left ^ 1 << i, i)); } return memo[left][pre] = res; } public int min(int a, int b){ return a < b ? a : b; } }
golang 解法, 执行用时: 200 ms, 内存消耗: 6.4 MB, 提交时间: 2023-06-28 09:33:27
func minimumIncompatibility(nums []int, k int) int { n := len(nums) if k == n { return 0 } cnt := make([]int, n+1) for _, num := range nums { cnt[num]++ if cnt[num] > k { // 存在某个数的数量超过k个,直接返回-1 return -1 } } m, div := 1<<uint(n), n/k f, sum := make([]int, m), make([]int, m) for i := range sum { // 预处理可以划分为同一个子集的所有情况 sum[i] = 1000 if bits.OnesCount(uint(i)) == div { curSum, curMax, curMin := 0, 0, n for j := i; j > 0; j ^= j & -j { // 参考树状数组的get 从低到高遍历i的每一个1 jj := bits.TrailingZeros(uint(j)) curSum |= 1 << uint(nums[jj]) curMax, curMin = max(curMax, nums[jj]), min(curMin, nums[jj]) } if bits.OnesCount(uint(curSum)) == div { sum[i] = curMax - curMin } } } for mask := 1; mask < m; mask++ { if bits.OnesCount(uint(mask))%div == 0 { // 只有mask中的1的数量可以被div整除,mask才可以进行有效的状态转移 f[mask] = 1000 for sub := mask; sub > 0; sub = (sub - 1) & mask { f[mask] = min(f[mask], f[mask^sub]+sum[sub]) } } } if f[m-1] == 1000 { return -1 } return f[m-1] } func min(a int, b int) int { if a < b { return a }; return b } func max(a int, b int) int { if a > b { return a }; return b }
python3 解法, 执行用时: 112 ms, 内存消耗: 24.3 MB, 提交时间: 2023-06-28 09:29:54
class Solution: def minimumIncompatibility(self, a: List[int], k: int) -> int: from collections import Counter if any(c > k for c in Counter(a).values()): # 鸽巢原理 return -1 n = len(a) size = n // k a.sort() # 排序,便于判断重复 @cache def dfs(left: int, pre: int) -> int: if left == 0: return 0 if left.bit_count() % size == 0: # 创建一个新的组 lb = left & -left # 选择 lowbit 作为第一个数 return dfs(left ^ lb, lb.bit_length() - 1) res = inf last = a[pre] for i in range(pre + 1, n): # 枚举这个组的下一个数 if left >> i & 1 and a[i] != last: # 组内不能有重复数字,且 a 中重复数字只需枚举一次 last = a[i] res = min(res, last - a[pre] + dfs(left ^ (1 << i), i)) return res return dfs((1 << n) - 2, 0)