Leetcode 1838最高频元素的频数
问题描述
- 题目原文:
元素的 频数 是该元素在一个数组中出现的次数。
给你一个整数数组 nums 和一个整数k 。在一步操作中,你可以选择 nums 的一个下标,并将该下标对应元素的值增加 1 。
执行最多 k 次操作后,返回数组中最高频元素的 最大可能频数
来源:力扣(LeetCode)
- 参数要求:
1 <= nums.length <= 1 0 5 10^5 105
1 <= nums[i] <= 1 0 5 10^5 105
1 <= k <= 1 0 5 10^5 105
思路
- 一个无序的数组,没有什么太好的思路,因此尝试改变数组的形式。
- 因为数组的没有规定顺序(递增或者递减),所以首先判断如果改变数组元素的顺序是否影响结果。如果不影响,将数组转换成有序递增的。
- 我们在这时候很容易发现如果采用答案在数组中变成连续的,因此尝试采用滑动窗口。
- 设置滑动窗口为[l,r],将r作为区间的基准,即所有元素通过增加1的操作变成r,统计需要的次数count。
- 如果count<=k说明当前的区间是合适的,可以将他和我们记录的结果进行比较,选择一个较大的数,然后r继续向右移动。
- 如果count>k说明当前的区间太大,必须要"丢"掉左边的一部分元素(l向右移),重新开始计算count。
- 上面移动边界的时候重新计算count的时候,说的有一些语焉不详,不太会画图,文字表述有一些抽象,如果有朋友参考的话,可以自己画图试试看。
代码
- 滑动窗口
public int maxFrequency(int[] nums, int k) {
Arrays.sort(nums);
int res = 1;
int l = 0;
int r = 0;
int count = 0;
int len = nums.length;
while (l<=r&&r<=len-1){
if (count<=k){//移动右边界
r++;
if (r>len-1){
break;
}
count += (r-l)*(nums[r]-nums[r-1]);
}
else{//移动左边界
l++;
if (l>r){
break;
}
count -= nums[r]-nums[l-1];
}
if (count<=k){//有效的话,进行判断取最大值
res = Math.max(res,r-l+1);
System.out.println(nums[r]);
}
}
return res;
}
- 滑动窗口+前缀数组(这里贴一份前缀数组的代码,思路大同小异,只是在count的计算上有差异)
int[] nums;
int[] arr;
public int maxFrequency(int[] nums, int k) {
Arrays.sort(nums);
int len = nums.length;
this.arr = new int[len];
this.nums = nums;
arr[0] = 0;
for (int i = 1; i < len; i++) {
arr[i] = arr[i-1] + i*(nums[i]-nums[i-1]);
}
int r = 0;
int l = -1;
int res = 1;
while (l<r&&r<=len-1){
int call_ret = getInterVals(l,r);
if (call_ret<=k){
r++;
if (r>=len){
break;
}
}
else{
l++;
}
int count = getInterVals(l,r);
if (count<=k&&res<r-l){
res = r-l;
}
}
return res;
}
//获取区间(l,r]
private int getInterVals(int l,int r){
if (l==-1){
return arr[r];
}
else {
return arr[r]-arr[l] - (nums[r]-nums[l])*(l+1);
}
}