Every day a Leetcode
题目来源:2856. 删除数对后的最小数组长度
解法1:哈希 + 分类讨论
假设数组 nums 中元素 x 出现次数最多,其出现次数为 maxCount。
分类讨论:
- 如果 2 * maxCount > n,其余所有 n − maxCount 个数都要与 x 消除,所以最后剩下 n - 2 * (n-maxCount) = 2 * maxCount - n 个数。
- 如果 2 * maxCount <= n 且 n 是偶数,那么可以把其余数消除至剩下 maxCount 个数,然后再和 x 消除,最后剩下 0 个数。
- 如果 2 * maxCount <= n 且 n 是奇数,同上,最后剩下 1 个数。
代码:
/*
* @lc app=leetcode.cn id=2856 lang=cpp
*
* [2856] 删除数对后的最小数组长度
*/
// @lc code=start
// 哈希 + 分类讨论
class Solution
{
public:
int minLengthAfterRemovals(vector<int> &nums)
{
// 特判
if (nums.empty())
return 0;
int n = nums.size();
// 统计数组 nums 中各元素的出现次数
unordered_map<int, int> cnt;
for (int &num : nums)
cnt[num]++;
int maxCount = 0;
for (auto &[_, c] : cnt)
maxCount = max(maxCount, c);
return max(2 * maxCount - n, n % 2);
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(n),其中 n 是数组 nums 的元素个数。
空间复杂度:O(n),其中 n 是数组 nums 的元素个数。
解法2:二分查找 + 分类讨论
但我们还可以更快!
由于数组 nums 是有序的,如果 maxCount 超过数组长度的一半,那么 nums[n/2] 一定是出现次数最多的那个数!
可以用二分查找在 O(logn) 的时间计算 nums[n/2] 第一次和最后一次出现的位置,从而算出 maxCount。
代码:
// 二分查找 + 分类讨论
class Solution
{
public:
int minLengthAfterRemovals(vector<int> &nums)
{
// 特判
if (nums.empty())
return 0;
int n = nums.size();
int x = nums[n / 2];
int maxCount = upper_bound(nums.begin(), nums.end(), x) -
lower_bound(nums.begin(), nums.end(), x);
if (maxCount > n / 2)
return 2 * maxCount - n;
return n % 2;
}
};
结果:
复杂度分析:
时间复杂度:O(logn),其中 n 是数组 nums 的元素个数。
空间复杂度:O(1)。