题目描述
元素的 频数 是该元素在一个数组中出现的次数。
给你一个整数数组 nums
和一个整数 k
。在一步操作中,你可以选择 nums
的一个下标,并将该下标对应元素的值增加 1
。
执行最多 k
次操作后,返回数组中最高频元素的 最大可能频数。
样例
输入:nums = [1,2,4], k = 5
输出:3
解释:对第一个元素执行 3 次递增操作,对第二个元素执 2 次递增操作,此时 nums = [4,4,4]。
4 是数组中最高频元素,频数是 3。
输入:nums = [1,4,8,13], k = 5
输出:2
解释:存在多种最优解决方案:
- 对第一个元素执行 3 次递增操作,此时 nums = [4,4,8,13]。4 是数组中最高频元素,频数是 2。
- 对第二个元素执行 4 次递增操作,此时 nums = [1,8,8,13]。8 是数组中最高频元素,频数是 2。
- 对第三个元素执行 5 次递增操作,此时 nums = [1,4,13,13]。13 是数组中最高频元素,频数是 2。
输入:nums = [3,9,6], k = 2
输出:1
限制
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5
1 <= k <= 10^5
算法
(贪心,双指针) $O(n \log n)$
- 将数组从小到大排序。
- 容易证明,拥有最高频元素的数字一定出现在当前数组中。不然的话,假设最高频的数字为
x
,则数组中必定存在一个数字最大的数字y
,满足y < x
。我们将最高频的数字改为y
时,并不会破坏题目的条件,且答案不变,所以贪心的结论正确。 - 接下来,使用双指针求解。对于每个位置 $r$,都找到尽可能小的位置 $l$,满足区间 $[l, r]$ 的数字都变为 $nums(r)$ 时的总操作次数不超过 $k$。
- 注意到 $l$ 是随着 $r$ 的增大单调不减的。
时间复杂度
- 排序后,双指针扫描,故总时间复杂度为 $O(n \log n)$。
空间复杂度
- 仅需要常数的额外空间。
C++ 代码
#define LL long long
class Solution {
public:
int maxFrequency(vector<int>& nums, int k) {
const int n = nums.size();
sort(nums.begin(), nums.end());
int ans = 1;
LL need = 0;
for (int l = 0, r = 1; r < n; r++) {
need += (LL)(r - l) * (nums[r] - nums[r - 1]);
while (need > k) {
need -= nums[r] - nums[l];
l++;
}
ans = max(ans, r - l + 1);
}
return ans;
}
};
可以用三分做吗?
在能保证是单峰函数的情况下,推荐用差值二分的方法替代三分。整数三分边界是有问题的,所以三分一般用在实数域
谢谢 管理员