Description
给定一个长为\(n\)的数组\(a\),提供2种操作:
- 选择2个相同元素并消去。
- 选择3个相同元素并消去。
求最小操作次数,使得数组为空。若不存在方案则返回\(-1\)。
Constraints
- \(1 \le n \le 10^5\)
- \(1 \le a_i \le 10^6\)
Solution
先观察一下:
- 2和3互质,公倍数是6。
- 每组相同元素独立统计(因为下标无关)。
- 只要频率不是1,那么必然有解(因为2和3包含了奇数和偶数)。
再转换题意:一个数的出现频率可构造为\(i \times 2 + j \times 3\),求最小的\(i+j\)。
当我尝试贪心的馊主意时就蛋疼了:
- 能不能贪心的全部抠掉3再抠2?一个反例是4,先抠3就无解,而抠两个2才是正解。
- 那我抠6的倍数?仍存在fvcking的反例13,使得余1。
然后我生气了,正着不行就反过来吧。根据结论3。当余1时:用2补成一个3,或者用3补成两个2。
Code
class Solution {
public:
int minOperations(vector<int>& nums) {
using umap = unordered_map<int, int>;
umap cnts, rcnts;
for(auto v : nums) cnts[v]++;
for(auto [_, n] : cnts) rcnts[n]++;
if(rcnts.count(1)) return -1;
int ans = 0;
for(auto [n_const, c] : rcnts) {
int t = 0;
int n = n_const;
int _2 = 0;
int _3 = 0;
if(n >= 3) {
_3 = n / 3;
n -= _3 * 3;
t += _3;
}
if(n >= 2) {
_2 = n / 2;
n -= _2 * 2;
t += _2;
}
if(n == 1) {
t += !_2;
}
ans += t * c;
}
return ans;
}
};
Link
LeetCode-2870 Minimum Number of Operations to Make Array Empty