LeetCode 题解工作台

求出 MK 平均值

给你两个整数 m 和 k ,以及数据流形式的若干整数。你需要实现一个数据结构,计算这个数据流的 MK 平均值 。 MK 平均值 按照如下步骤计算: 如果数据流中的整数少于 m 个, MK 平均值 为 -1 ,否则将数据流中最后 m 个元素拷贝到一个独立的容器中。 从这个容器中删除最小的 k 个数和最…

category

5

题型

code_blocks

4

代码语言

hub

3

相关题

当前训练重点

困难 · 堆

bolt

答案摘要

我们可以维护以下数据结构或变量: - 一个长度为 的队列 ,其中队首元素为最早加入的元素,队尾元素为最近加入的元素;

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 堆 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你两个整数 m 和 k ,以及数据流形式的若干整数。你需要实现一个数据结构,计算这个数据流的 MK 平均值 。

MK 平均值 按照如下步骤计算:

  1. 如果数据流中的整数少于 m 个,MK 平均值 为 -1 ,否则将数据流中最后 m 个元素拷贝到一个独立的容器中。
  2. 从这个容器中删除最小的 k 个数和最大的 k 个数。
  3. 计算剩余元素的平均值,并 向下取整到最近的整数 。

请你实现 MKAverage 类:

  • MKAverage(int m, int k) 用一个空的数据流和两个整数 m 和 k 初始化 MKAverage 对象。
  • void addElement(int num) 往数据流中插入一个新的元素 num 。
  • int calculateMKAverage() 对当前的数据流计算并返回 MK 平均数 ,结果需 向下取整到最近的整数 。

 

示例 1:

输入:
["MKAverage", "addElement", "addElement", "calculateMKAverage", "addElement", "calculateMKAverage", "addElement", "addElement", "addElement", "calculateMKAverage"]
[[3, 1], [3], [1], [], [10], [], [5], [5], [5], []]
输出:
[null, null, null, -1, null, 3, null, null, null, 5]

解释:
MKAverage obj = new MKAverage(3, 1); 
obj.addElement(3);        // 当前元素为 [3]
obj.addElement(1);        // 当前元素为 [3,1]
obj.calculateMKAverage(); // 返回 -1 ,因为 m = 3 ,但数据流中只有 2 个元素
obj.addElement(10);       // 当前元素为 [3,1,10]
obj.calculateMKAverage(); // 最后 3 个元素为 [3,1,10]
                          // 删除最小以及最大的 1 个元素后,容器为 [3]
                          // [3] 的平均值等于 3/1 = 3 ,故返回 3
obj.addElement(5);        // 当前元素为 [3,1,10,5]
obj.addElement(5);        // 当前元素为 [3,1,10,5,5]
obj.addElement(5);        // 当前元素为 [3,1,10,5,5,5]
obj.calculateMKAverage(); // 最后 3 个元素为 [5,5,5]
                          // 删除最小以及最大的 1 个元素后,容器为 [5]
                          // [5] 的平均值等于 5/1 = 5 ,故返回 5

 

提示:

  • 3 <= m <= 105
  • 1 <= k*2 < m
  • 1 <= num <= 105
  • addElement 与 calculateMKAverage 总操作次数不超过 105 次。
lightbulb

解题思路

方法一:有序集合 + 队列

我们可以维护以下数据结构或变量:

  • 一个长度为 mm 的队列 qq,其中队首元素为最早加入的元素,队尾元素为最近加入的元素;
  • 三个有序集合,分别为 lolo, midmid, hihi,其中 lolo 和 hihi 分别存储最小的 kk 个元素和最大的 kk 个元素,而 midmid 存储剩余的元素;
  • 一个变量 ss,维护 midmid 中所有元素的和;
  • 部分编程语言(如 Java, Go)额外维护两个变量 size1size1 和 size3size3,分别表示 lolo 和 hihi 中元素的个数。

调用 addElement(num)addElement(num) 函数时,顺序执行以下操作:

  1. 如果 lolo 为空,或者 num≤max(lo)num \leq max(lo),则将 numnum 加入 lolo 中;否则如果 hihi 为空,或者 num≥min(hi)num \geq min(hi),则将 numnum 加入 hihi 中;否则将 numnum 加入 midmid 中,同时将 numnum 的值加到 ss 中。
  2. 接下来将 numnum 加入队列 qq 中,如果此时队列 qq 的长度大于 mm,则将队首元素 xx 从队列 qq 中移除,接下来从 lolo, midmid 或 hihi 中选择其中一个包含 xx 的集合,将 xx 从该集合中移除,如果该集合为 midmid,则将 ss 减去 xx 的值。
  3. 如果 lolo 的长度大于 kk,则循环将 lolo 中的最大值 max(lo)max(lo) 从 lolo 中移除,将 max(lo)max(lo) 加入 midmid 中,同时将 ss 加上 max(lo)max(lo) 的值。
  4. 如果 hihi 的长度大于 kk,则循环将 hihi 中的最小值 min(hi)min(hi) 从 hihi 中移除,将 min(hi)min(hi) 加入 midmid 中,同时将 ss 加上 min(hi)min(hi) 的值。
  5. 如果 lolo 的长度小于 kk,并且 midmid 不为空,则循环将 midmid 中的最小值 min(mid)min(mid) 从 midmid 中移除,将 min(mid)min(mid) 加入 lolo 中,同时将 ss 减去 min(mid)min(mid) 的值。
  6. 如果 hihi 的长度小于 kk,并且 midmid 不为空,则循环将 midmid 中的最大值 max(mid)max(mid) 从 midmid 中移除,将 max(mid)max(mid) 加入 hihi 中,同时将 ss 减去 max(mid)max(mid) 的值。

调用 calculateMKAverage()calculateMKAverage() 函数时,如果 qq 的长度小于 mm,则返回 −1-1,否则返回 sm−2k\frac{s}{m - 2k}。

时间复杂度方面,每次调用 addElement(num)addElement(num) 函数的时间复杂度为 O(log⁡m)O(\log m),每次调用 calculateMKAverage()calculateMKAverage() 函数的时间复杂度为 O(1)O(1)。空间复杂度为 O(m)O(m)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class MKAverage:
    def __init__(self, m: int, k: int):
        self.m = m
        self.k = k
        self.s = 0
        self.q = deque()
        self.lo = SortedList()
        self.mid = SortedList()
        self.hi = SortedList()

    def addElement(self, num: int) -> None:
        if not self.lo or num <= self.lo[-1]:
            self.lo.add(num)
        elif not self.hi or num >= self.hi[0]:
            self.hi.add(num)
        else:
            self.mid.add(num)
            self.s += num
        self.q.append(num)
        if len(self.q) > self.m:
            x = self.q.popleft()
            if x in self.lo:
                self.lo.remove(x)
            elif x in self.hi:
                self.hi.remove(x)
            else:
                self.mid.remove(x)
                self.s -= x
        while len(self.lo) > self.k:
            x = self.lo.pop()
            self.mid.add(x)
            self.s += x
        while len(self.hi) > self.k:
            x = self.hi.pop(0)
            self.mid.add(x)
            self.s += x
        while len(self.lo) < self.k and self.mid:
            x = self.mid.pop(0)
            self.lo.add(x)
            self.s -= x
        while len(self.hi) < self.k and self.mid:
            x = self.mid.pop()
            self.hi.add(x)
            self.s -= x

    def calculateMKAverage(self) -> int:
        return -1 if len(self.q) < self.m else self.s // (self.m - 2 * self.k)


# Your MKAverage object will be instantiated and called as such:
# obj = MKAverage(m, k)
# obj.addElement(num)
# param_2 = obj.calculateMKAverage()
speed

复杂度分析

指标值
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Look for the candidate's understanding of sliding window techniques.

  • question_mark

    Gauge their ability to optimize the insertion and average calculation process.

  • question_mark

    Check if the candidate considers edge cases where `m` is small or the stream has fewer than `m` elements.

warning

常见陷阱

外企场景
  • error

    Not handling cases where the number of elements in the stream is less than `m` before the first `MKAverage` query.

  • error

    Inefficient recalculation of the average by re-sorting or scanning all `m` elements.

  • error

    Overcomplicating the solution by using unnecessary data structures, resulting in unnecessary time or space complexity.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Implement the solution using a deque to avoid sorting and ensure faster operations for average calculation.

  • arrow_right_alt

    Modify the problem to handle updates to the stream where elements can be removed or modified.

  • arrow_right_alt

    Extend the problem to calculate the MKAverage over different window sizes dynamically.

help

常见问题

外企场景

求出 MK 平均值题解:堆 | LeetCode #1825 困难