【力扣】DP/贪心:1681. 最小不兼容性
文章目录
- 【力扣】DP/贪心:1681. 最小不兼容性
- 1. 题目描述
- 2. 解题
- 2.1 不可行
- 2.2 DP(预处理 + 状态压缩 + 动态规划)
- 参考
1. 题目描述
给你一个整数数组 nums 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。
- 一个子集的 不兼容性 是 该子集里面最大值和最小值的差。
请你返回将数组分成 k 个子集后,各子集 不兼容性 的 和 的 最小值 ,如果无法分成分成 k 个子集,返回 -1 。
子集的定义是数组中一些数字的集合,对数字顺序没有要求。
2. 解题
2.1 不可行
首先想到先排个序,再贪心就好了,但是这种情况【1,1,2,2,3,3】,就得回溯。
-
改进,但未实现。
- 先判断是否满足条件,即判断每个数的个数是否小于 k,不满足直接输出-1;
- 然后排序+贪心?+回溯+剪枝。
-
之前版本代码(错误的)。
class Solution {
public:
int minimumIncompatibility(vector<int>& nums, int k) {
int n = nums.size();
int l = n / k;
sort(nums.begin(), nums.end());
vector<int> flags(n, 0);
vector<int> cur(l, 0);
int flag = 0;
int sum = 0;
for(int i=0; i<n; i++){
cout<<nums[i];
}
cout<<endl;
for(int i=0; i<n; i++){
cout<<n<<" 00000"<<endl;
if(flags[i]==1){
continue;
}
int h = i;
int cnt = 0;
int ct = 0;
while(cnt<l){
int f = 0;
if(flags[h]==1){
h++;
continue;
}
for(int j=0; j<cnt; j++){
cout<<"abc"<<j<<h<<endl;
cout<<cur[j]<<nums[h]<<endl;
if(cur[j]==nums[h]){
f = 1;
break;
}
}
cout<<f<<'h'<<h<<endl;
if(flag==1) break;
if(f==0){
cur[cnt] = nums[h];
cnt++;
flags[i] = 1;
if(h<n-1){
h++;
}
else{
break;
}
}
else{
h++;
}
}
sum += (cur[l-1] - cur[0]);
}
if(flag == 1){
sum = -1;
}
return sum;
}
};
2.2 DP(预处理 + 状态压缩 + 动态规划)
- 正确题解是DP(预处理 + 状态压缩 + 动态规划)
class Solution:
def minimumIncompatibility(self, nums: List[int], k: int) -> int:
n = len(nums)
m = n // k
g = [-1] * (1 << n)
for i in range(1, 1 << n):
if i.bit_count() != m:
continue
s = set()
mi, mx = 20, 0
for j, x in enumerate(nums):
if i >> j & 1:
if x in s:
break
s.add(x)
mi = min(mi, x)
mx = max(mx, x)
if len(s) == m:
g[i] = mx - mi
f = [inf] * (1 << n)
f[0] = 0
for i in range(1 << n):
if f[i] == inf:
continue
s = set()
mask = 0
for j, x in enumerate(nums):
if (i >> j & 1) == 0 and x not in s:
s.add(x)
mask |= 1 << j
if len(s) < m:
continue
j = mask
while j:
if g[j] != -1:
f[i | j] = min(f[i | j], f[i] + g[j])
j = (j - 1) & mask
return f[-1] if f[-1] != inf else -1
参考
【1】https://leetcode.cn/problems/minimum-incompatibility/description/