描述
元素的 频数 是该元素在一个数组中出现的次数。
给你一个整数数组 nums 和一个整数 k 。在一步操作中,你可以选择 nums 的一个下标,并将该下标对应元素的值增加 1 。
执行最多 k 次操作后,返回数组中最高频元素的 最大可能频数 。
样例
示例 1:输入:nums = [1,2,4], k = 5输出:3解释:对第一个元素执行 3 次递增操作,对第二个元素执 2 次递增操作,此时 nums = [4,4,4] 。4 是数组中最高频元素,频数是 3 。示例 2:输入: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 。示例 3:输入:nums = [3,9,6], k = 2输出:1
提示
1 <= nums.length <= 1051 <= nums[i] <= 1051 <= k <= 105
解题思路
排序 + 前缀和 + 二分 + 滑动窗口
- 对原数组 nums 进行从小到大排序
- 二分答案 lenlen 作为窗口长度
- 利用前缀和计算真实区间的和
- 比较目标区间和和真实区间和的差值
AC代码
class Solution {int[] nums, sum;int n, k;public int maxFrequency(int[] _nums, int _k) {nums = _nums;k = _k;n = nums.length;Arrays.sort(nums);sum = new int[n + 1];for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1];int l = 0, r = n;while (l < r) {int mid = l + r + 1 >> 1;if (check(mid)) l = mid;else r = mid - 1;}return r;}boolean check(int len) {for (int l = 0; l + len - 1 < n; l++) {int r = l + len - 1;int cur = sum[r + 1] - sum[l];int t = nums[r] * len;if (t - cur <= k) return true;}return false;}}
时间复杂度
- 时间复杂度:排序的复杂度为 O(nlogn);计算前缀和数组复杂度为 O(n);check 函数的复杂度为O(n),因此二分复杂度为 O(nlogn)。整体复杂度为 O(nlogn)
- 空间复杂度:O(n)
