题目
元素的 频数 是该元素在一个数组中出现的次数。
给你一个整数数组 nums 和一个整数 k 。在一步操作中,你可以选择 nums 的一个下标,并将该下标对应元素的值增加 1 。
执行最多 k 次操作后,返回数组中最高频元素的 最大可能频数 。
思路
自己是没有什么思路的,知道说应该要进行一个排序,但是不知道应该使用哪一种算法进行解决!
看了题解,总算有点点思路!
操作数组后,一定是将所有数字变为其中的某一个数字。提示1解释得挺清楚的,因为结果只是求最高频元素的频数,这个时候,我们统一变成一个比最大那个数。在结果看来,我们只是影响了最高频元素的大小,并不影响最高频元素的频数
提示2,优先操作距离目标值最近的元素,因为我们对数组进行了一个排序,数组一定是从小到大进行排序的,比如右边的数是5,左边的是1,中间的是3,那肯定是操作3使得3变成5的步数比操作1变成5的步数要少!
这里的推导要自己去推导一下,就是在原有的基础上,假设向右移动,那么就会增加总的步数,向左移动,会减少总的步数。【每次都是将某个数字左边的所有数字变为该数字】,这样子,每次拿当前频数与操作后结果的频数进行一个比较,最终可以获得将步数k利用到极致的情况下,所能够获得的最高频元素的频数!
代码
class Solution {
public int maxFrequency(int[] nums, int k) {
// 对数组进行一个升序排序
Arrays.sort(nums);
// 数组的长度
int length = nums.length;
// 需要操作的总步数,必须保证这个数小于等于k才符合条件
long total = 0;
// 左指针为0,右指针为1
int l = 0;
int ans = 1;
for (int i= 1; i < length; ++i)
{
total += (long) (nums[i] - nums[i-1]) * (i-l);
// 当总步数大于k时,移动左指针缩小步数
while (total > k)
{
// 根据推算,不动右指针,右移左指针会减少这么多步数
total-= nums[i]-nums[l];
++l;
}
ans = Math.max(ans,i-l + 1);
}
return ans;
}
}
结果
结果很强,从来对滑动窗口没什么概念,今天算是见识到了滑动窗口的好处。如果使用暴力,真的浪费了巨大的计算量!