0
点赞
收藏
分享

微信扫一扫

一刷281-滑动窗口-1838. 最高频元素的频数(m)

weednoah 2022-04-04 阅读 20
leetcode
题目:
元素的 频数 是该元素在一个数组中出现的次数。

给你一个整数数组 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 <= 105
1 <= nums[i] <= 105
1 <= k <= 105
----------------------
思路:
翻译:求一个数组中,如何使用给定的次数k,将数组中某些元素执行k次的加1操作,
使得数组中相同元素尽可能地多。结果要的是这个元素的频数。

在次数有限的情况,要找到变化后最高频的元素,那这个元素应当已经在数组中出现过,
这样我们就不需要考虑对这个元素进行操作,
操作次数会比用数组中已有元素构造出一个数组没有的元素的次数要少。
那么,对什么样的元素进行加1操作呢?

应当对【离我们选定的最高频元素最近的元素】进行加1操作。这个最近指的是,差值最近。
想到这里,我们能否对数组进行排序呢?答案是肯定的,因为题目对数组中元素的顺序并没有要求,
他不要求我们去求这个最大频数的区间下标,所以为了方便,我们可以快乐地进行排序

如何暴力求解呢?
天然的想法是,我们可以将数组中的每个元素都当作目标元素,对其它元素进行操作,
从而得到每次操作后的频数,对该频数取最大值,即可。

但是数组长度∈[1,10^5],对于每选定一个元素,都要遍历其他所有元素,
所以这种方法大概率会超时的,需要进行优化。

那么,怎么优化呢?
换个思路去理解这道题,就是说:
【如何在有限的k次操作中,尽可能多的让某个区间中的值相等,求这个最长区间的长度】。
那么,这种尽量延长区间的题意,就能很自然联想到区间问题利器:【滑动窗口】,
我们试图用滑动窗口的思想来思考一下。

滑动窗口解题前你需要考虑清楚的问题
我们尽可能地右移扩大窗口,当窗口中的元素不满足要求时,再缩小窗口。
由于进行了排序,窗口中的最大值,应当在窗口的【最右侧】,为什么是最大值?
因为我们要进行【加1】操作,所以自然是用小的数去加1,我们选择这个最大值作为基准。

窗口扩大时,需要对什么数据进行更新?
扩大窗口时,应当计算当前窗口左侧元素需要操作多少次才能和最右侧元素值相等。

窗口什么时候应该停止扩大?
当该窗口中元素操作次数大于给定的k时,应当停止扩大窗口。

窗口缩小时,需要对什么数据进行更新?
从操作次数中,减去【最左侧移出窗口的元素变为最右侧元素所需要的操作次数】

最终要的结果,应在在什么时候获得?
当操作次数没有超过k次的时候,就可以更新最大频数,最大的频数就是【当前窗口长度】。
这些问题想清楚之后,我们离动手写代码只差一步了,就是明确关键的计算代码应当如何来表示。
最关键的就是【操作次数的计算】,这时候只需要画一个图,就立刻能懂怎么算了。
计算操作次数的公式:
count += (nums[right] - nums[right - 1]) * (right - left);

其中:

nums[right] - nums[right - 1]表示窗口右区间的数与它前一个数的差值,
这个差值也就是nums[right - 1]变为nums[right]的操作次数。

(right - left)表示这个区间里,有几个数需要被进行操作。
那么,这两项相乘即为区间内的操作次数。

【举例说明】:
当nums[right] = 4时,区间[0, 1]内的操作次数 = nums[right - 1]
变为nums[right]需要的次数,("1"变为"4"的次数)
当nums[right] = 8时,区间[0, 2]内的操作次数 = nums[right - 1]
变为nums[right]需要的次数乘区间长度,即两个"4"变为"8"的长度,
此时nums[0]经由上一次的操作已经变成了"4"。
那么总的操作次数,应当是每一次计算后的累加值。

在这里插入图片描述

class Solution {
    public int maxFrequency(int[] nums, int k) {
        Arrays.sort(nums);//排序
        int left = 0;//双指针
        int right = 1;//初始化为1 是因为while循环内 right - 1
        int count = 0;//操作次数,用来与 比较
        int maxLen = 1;//结果集:数组中最高频元素的最大可能频数
        while (right < nums.length) {//遍历
            count += (nums[right] - nums[right - 1]) * (right - left);
            while (count > k) {//当已操作次数 大于 k时,移动滑动窗口
                count -= nums[right] - nums[left];
                left++;
            }
            maxLen = Math.max(maxLen, right - left + 1);
            right++;
        }
        return maxLen;
    }
}

LC

举报

相关推荐

0 条评论