题目描述
思路解析动画文字版
记住「排序 → 抬平代价 = 最大值×长度 − 窗口和 → 代价超 k 就左缩、记最长」,下面每一格都在套它。
第一步排序。排完序相邻的数才挨在一起,抬平代价最小,滑动窗口也才能稳稳伸缩。下面窗口从空开始,右指针一格格扩。
右指针到第 0 位(值 1)。把窗口里 1 个数都抬到最大的 1,要花 1×1 减去窗口和 1,也就是 0 次操作。没超过 k=10,这段抬得平。
窗口 [0, 0] 抬平只要 0 次(≤10),长度 1。比之前还长,最高频数刷新成 1。
右指针到第 1 位(值 2)。把窗口里 2 个数都抬到最大的 2,要花 2×2 减去窗口和 3,也就是 1 次操作。没超过 k=10,这段抬得平。
窗口 [0, 1] 抬平只要 1 次(≤10),长度 2。比之前还长,最高频数刷新成 2。
右指针到第 2 位(值 3)。把窗口里 3 个数都抬到最大的 3,要花 3×3 减去窗口和 6,也就是 3 次操作。没超过 k=10,这段抬得平。
窗口 [0, 2] 抬平只要 3 次(≤10),长度 3。比之前还长,最高频数刷新成 3。
右指针到第 3 位(值 4)。把窗口里 4 个数都抬到最大的 4,要花 4×4 减去窗口和 10,也就是 6 次操作。没超过 k=10,这段抬得平。
窗口 [0, 3] 抬平只要 6 次(≤10),长度 4。比之前还长,最高频数刷新成 4。
右指针到第 4 位(值 5)。把窗口里 5 个数都抬到最大的 5,要花 5×5 减去窗口和 15,也就是 10 次操作。没超过 k=10,这段抬得平。
窗口 [0, 4] 抬平只要 10 次(≤10),长度 5。比之前还长,最高频数刷新成 5。
右指针到第 5 位(值 6)。把窗口里 6 个数都抬到最大的 6,要花 6×6 减去窗口和 21,也就是 15 次操作。它 > k=10(红),操作不够,下一步得左缩。
左指针右移 1 步、把移出的数从和里减掉,代价降到 10(≤10)。现在窗口 [1, 5] 能全抬成 6、长度 5。没超过已记的最长 5,保持。
右指针到第 6 位(值 7)。把窗口里 6 个数都抬到最大的 7,要花 7×6 减去窗口和 27,也就是 15 次操作。它 > k=10(红),操作不够,下一步得左缩。
左指针右移 1 步、把移出的数从和里减掉,代价降到 10(≤10)。现在窗口 [2, 6] 能全抬成 7、长度 5。没超过已记的最长 5,保持。
右指针到第 7 位(值 8)。把窗口里 6 个数都抬到最大的 8,要花 8×6 减去窗口和 33,也就是 15 次操作。它 > k=10(红),操作不够,下一步得左缩。
左指针右移 1 步、把移出的数从和里减掉,代价降到 10(≤10)。现在窗口 [3, 7] 能全抬成 8、长度 5。没超过已记的最长 5,保持。
右指针到第 8 位(值 9)。把窗口里 6 个数都抬到最大的 9,要花 9×6 减去窗口和 39,也就是 15 次操作。它 > k=10(红),操作不够,下一步得左缩。
左指针右移 1 步、把移出的数从和里减掉,代价降到 10(≤10)。现在窗口 [4, 8] 能全抬成 9、长度 5。没超过已记的最长 5,保持。
右指针到第 9 位(值 12)。把窗口里 6 个数都抬到最大的 12,要花 12×6 减去窗口和 47,也就是 25 次操作。它 > k=10(红),操作不够,下一步得左缩。
左指针右移 3 步、把移出的数从和里减掉,代价降到 7(≤10)。现在窗口 [7, 9] 能全抬成 12、长度 3。没超过已记的最长 5,保持。
扫完全程,能在 10 次操作内抬成同一个值的最长窗口长 5,所以最高频数是 5。排序加滑窗,一遍就找到了,不用枚举抬哪个值。
边界:k=0 时数排序后本来相等的段;单元素是 1。
面试常考:代价单调性(可滑窗的前提)+ 最长窗口长度即最高频数。
参考代码
from typing import Listclass Solution: def maxFrequency(self, nums: List[int], k: int) -> int: nums.sort() left = total = ans = 0 for right, x in enumerate(nums): total += x while x * (right - left + 1) - total > k: total -= nums[left] left += 1 ans = max(ans, right - left + 1) return ans复杂度
- 时间:O(n log n),排序 O(n log n) 是瓶颈;之后左右指针各只前进一遍、滑窗 O(n)
- 空间:O(1),排序原地,只用 left/total/ans 几个变量(不计排序栈)
易错点
面试追问把动画讲成自己的话
追问为什么代价随窗口变长是单调不减的,从而能用滑动窗口?
追问答案为什么是最长窗口的长度?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
长度为 K 子数组中的最大和
LeetCode 2461 · 中等 · 沿着 滑动窗口套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题