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,其中 lolohihi 分别存储最小的 kk 个元素和最大的 kk 个元素,而 midmid 存储剩余的元素;
  • 一个变量 ss,维护 midmid 中所有元素的和;
  • 部分编程语言(如 Java, Go)额外维护两个变量 size1size1size3size3,分别表示 lolohihi 中元素的个数。

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

  1. 如果 lolo 为空,或者 nummax(lo)num \leq max(lo),则将 numnum 加入 lolo 中;否则如果 hihi 为空,或者 nummin(hi)num \geq min(hi),则将 numnum 加入 hihi 中;否则将 numnum 加入 midmid 中,同时将 numnum 的值加到 ss 中。
  2. 接下来将 numnum 加入队列 qq 中,如果此时队列 qq 的长度大于 mm,则将队首元素 xx 从队列 qq 中移除,接下来从 lolo, midmidhihi 中选择其中一个包含 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,否则返回 sm2k\frac{s}{m - 2k}

时间复杂度方面,每次调用 addElement(num)addElement(num) 函数的时间复杂度为 O(logm)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 困难