LeetCode 题解工作台

执行操作使频率分数最大

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 你可以对数组执行 至多 k 次操作: 从数组中选择一个下标 i ,将 nums[i] 增加 或者 减少 1 。 最终数组的频率分数定义为数组中众数的 频率 。 请你返回你可以得到的 最大 频率分数。 众数指的是数组中出现次数最多的数。…

category

5

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 二分·搜索·答案·空间

bolt

答案摘要

题目求的是在最多进行 次操作的情况下,我们能得到的众数的最大频率。如果我们将数组 按照从小到大的顺序排列,那么最好就是将一段连续的数字都变成同一个数,这样可以使得操作次数较少,并且众数的频率较高。 因此,我们不妨先对数组 进行排序。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 二分·搜索·答案·空间 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。

你可以对数组执行 至多 k 次操作:

  • 从数组中选择一个下标 i ,将 nums[i] 增加 或者 减少 1 。

最终数组的频率分数定义为数组中众数的 频率 。

请你返回你可以得到的 最大 频率分数。

众数指的是数组中出现次数最多的数。一个元素的频率指的是数组中这个元素的出现次数。

 

示例 1:

输入:nums = [1,2,6,4], k = 3
输出:3
解释:我们可以对数组执行以下操作:
- 选择 i = 0 ,将 nums[0] 增加 1 。得到数组 [2,2,6,4] 。
- 选择 i = 3 ,将 nums[3] 减少 1 ,得到数组 [2,2,6,3] 。
- 选择 i = 3 ,将 nums[3] 减少 1 ,得到数组 [2,2,6,2] 。
元素 2 是最终数组中的众数,出现了 3 次,所以频率分数为 3 。
3 是所有可行方案里的最大频率分数。

示例 2:

输入:nums = [1,4,4,2,4], k = 0
输出:3
解释:我们无法执行任何操作,所以得到的频率分数是原数组中众数的频率 3 。

 

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • 0 <= k <= 1014
lightbulb

解题思路

方法一:排序 + 前缀和 + 二分查找

题目求的是在最多进行 kk 次操作的情况下,我们能得到的众数的最大频率。如果我们将数组 numsnums 按照从小到大的顺序排列,那么最好就是将一段连续的数字都变成同一个数,这样可以使得操作次数较少,并且众数的频率较高。

因此,我们不妨先对数组 numsnums 进行排序。

接下来,我们再分析,如果一个频率 xx 是可行的,那么对于任意 yxy \le x,频率 yy 也是可行的,这存在着单调性。因此,我们可以通过二分查找,找到最大的满足条件的频率。

我们二分枚举频率,定义二分查找的左边界 l=0l = 0,右边界 r=nr = n,其中 nn 是数组的长度。每次二分查找的过程中,我们取中间值 mid=l+r+12mid = \lfloor \frac{l + r + 1}{2} \rfloor,然后判断 numsnums 中是否存在一个长度为 midmid 的连续子数组,使得这个子数组中的所有元素都变成这个子数组的中位数,且操作次数不超过 kk。如果存在,那么我们就将左边界 ll 更新为 midmid,否则我们就将右边界 rr 更新为 mid1mid - 1

为了判断是否存在这样的子数组,我们可以使用前缀和。我们首先定义两个指针 iijj,初始时 i=0i = 0, j=i+midj = i + mid。那么 nums[i]nums[i]nums[j1]nums[j - 1] 这一段的元素都变成 nums[(i+j)/2]nums[(i + j) / 2],所需要的操作次数为 left+rightleft + right,其中:

left=k=i(i+j)/21(nums[(i+j)/2]nums[k])=((i+j)/2i)×nums[(i+j)/2]k=i(i+j)/21nums[k]\begin{aligned} \textit{left} &= \sum_{k = i}^{(i + j) / 2 - 1} (nums[(i + j) / 2] - nums[k]) \\ &= ((i + j) / 2 - i) \times nums[(i + j) / 2] - \sum_{k = i}^{(i + j) / 2 - 1} nums[k] \end{aligned} right=k=(i+j)/2+1j(nums[k]nums[(i+j)/2])=k=(i+j)/2+1jnums[k](j(i+j)/2)×nums[(i+j)/2]\begin{aligned} \textit{right} &= \sum_{k = (i + j) / 2 + 1}^{j} (nums[k] - nums[(i + j) / 2]) \\ &= \sum_{k = (i + j) / 2 + 1}^{j} nums[k] - (j - (i + j) / 2) \times nums[(i + j) / 2] \end{aligned}

我们可以通过前缀和数组 ss 来计算 k=ijnums[k]\sum_{k = i}^{j} nums[k],从而在 O(1)O(1) 的时间内计算出 leftleftrightright

时间复杂度 O(n×logn)O(n \times \log n),空间复杂度 O(n)O(n)。其中 nn 是数组的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution:
    def maxFrequencyScore(self, nums: List[int], k: int) -> int:
        nums.sort()
        s = list(accumulate(nums, initial=0))
        n = len(nums)
        l, r = 0, n
        while l < r:
            mid = (l + r + 1) >> 1
            ok = False
            for i in range(n - mid + 1):
                j = i + mid
                x = nums[(i + j) // 2]
                left = ((i + j) // 2 - i) * x - (s[(i + j) // 2] - s[i])
                right = (s[j] - s[(i + j) // 2]) - ((j - (i + j) // 2) * x)
                if left + right <= k:
                    ok = True
                    break
            if ok:
                l = mid
            else:
                r = mid - 1
        return l
speed

复杂度分析

指标
时间complexity is O(n log n) for sorting plus O(n) per binary search check, leading to O(n log n + n log n) overall. Space complexity is O(1) extra if using in-place prefix sums, otherwise O(n) for storing prefix sums.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Notice that brute force O(n^2) checks will time out on large inputs.

  • question_mark

    Consider sorting first to simplify the operation calculations over subarrays.

  • question_mark

    Use binary search over the answer space to efficiently maximize frequency score.

warning

常见陷阱

外企场景
  • error

    Forgetting that operations must be counted cumulatively, not per element.

  • error

    Attempting to check every subarray without using sliding window optimization.

  • error

    Not handling large k values correctly, which can exceed naive iteration limits.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Restrict operations to only increase values and see how the optimal subarray changes.

  • arrow_right_alt

    Find the minimum k needed to achieve a target frequency score instead of maximizing it.

  • arrow_right_alt

    Apply the same pattern but with modulo operations for cyclic value adjustments.

help

常见问题

外企场景

执行操作使频率分数最大题解:二分·搜索·答案·空间 | LeetCode #2968 困难