|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[剑指 Offer II 041. 滑动窗口的平均值](https://leetcode.cn/problems/qIsx9U/solution/by-ac_oier-g5ha/)** ,难度为 **简单**。 |
| 4 | + |
| 5 | +Tag : 「模拟」、「队列」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +给定一个整数数据流和一个窗口大小,根据该滑动窗口的大小,计算滑动窗口里所有数字的平均值。 |
| 10 | + |
| 11 | +实现 `MovingAverage` 类: |
| 12 | + |
| 13 | +* `MovingAverage(int size)` 用窗口大小 `size` 初始化对象。 |
| 14 | +* `double next(int val)` 成员函数 `next` 每次调用的时候都会往滑动窗口增加一个整数,请计算并返回数据流中最后 `size` 个值的移动平均值,即滑动窗口里所有数字的平均值。 |
| 15 | + |
| 16 | +示例: |
| 17 | +``` |
| 18 | +输入: |
| 19 | +inputs = ["MovingAverage", "next", "next", "next", "next"] |
| 20 | +inputs = [[3], [1], [10], [3], [5]] |
| 21 | + |
| 22 | +输出: |
| 23 | +[null, 1.0, 5.5, 4.66667, 6.0] |
| 24 | + |
| 25 | +解释: |
| 26 | +MovingAverage movingAverage = new MovingAverage(3); |
| 27 | +movingAverage.next(1); // 返回 1.0 = 1 / 1 |
| 28 | +movingAverage.next(10); // 返回 5.5 = (1 + 10) / 2 |
| 29 | +movingAverage.next(3); // 返回 4.66667 = (1 + 10 + 3) / 3 |
| 30 | +movingAverage.next(5); // 返回 6.0 = (10 + 3 + 5) / 3 |
| 31 | +``` |
| 32 | + |
| 33 | +提示: |
| 34 | +* 1ドル <= size <= 1000$ |
| 35 | +* $-10^5 <= val <= 10^5$ |
| 36 | +* 最多调用 `next` 方法 10ドル^4$ 次 |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +### 双端队列 |
| 41 | + |
| 42 | +根据题意,我们可以使用变量 `n` 将初始化传入的 `size` 进行转存,同时使用「双端队列」来存储 `next` 所追加的值(添加到队列尾部),当双端队列所包含元素超过规定数量 `n` 时,我们从队列头部进行 `pop` 操作,整个维护过程使用变量 `sum` 记录当前包含的元素和。 |
| 43 | + |
| 44 | +利用 `next` 操作最多被调用 10ドル^4$ 次,我们可以使用直接开个 10ドル^4$ 数组来充当双端队列,使用两指针 `j` 和 `i` 分别指向队列的头部和尾部。 |
| 45 | + |
| 46 | +Java 代码: |
| 47 | +```Java |
| 48 | +class MovingAverage { |
| 49 | + int[] arr = new int[10010]; |
| 50 | + int n, sum, j, i; |
| 51 | + public MovingAverage(int size) { |
| 52 | + n = size; |
| 53 | + } |
| 54 | + public double next(int val) { |
| 55 | + sum += arr[i++] = val; |
| 56 | + if (i - j > n) sum -= arr[j++]; |
| 57 | + return sum * 1.0 / (i - j); |
| 58 | + } |
| 59 | +} |
| 60 | +``` |
| 61 | +Typescript 代码: |
| 62 | +```Typescript |
| 63 | +class MovingAverage { |
| 64 | + arr: number[] = new Array<number>(10010).fill(0) |
| 65 | + n: number = 0; sum: number = 0; i: number = 0; j: number = 0; |
| 66 | + constructor(size: number) { |
| 67 | + this.n = size |
| 68 | + } |
| 69 | + next(val: number): number { |
| 70 | + this.sum += this.arr[this.i++] = val |
| 71 | + if (this.i - this.j > this.n) this.sum -= this.arr[this.j++] |
| 72 | + return this.sum / (this.i - this.j) |
| 73 | + } |
| 74 | +} |
| 75 | +``` |
| 76 | +* 时间复杂度:$O(m),ドル其中 $m$ 为 `next` 操作的调用次数 |
| 77 | +* 空间复杂度:$O(n)$ |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +### 最后 |
| 82 | + |
| 83 | +这是我们「刷穿 LeetCode」系列文章的第 `剑指 Offer II 041` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 |
| 84 | + |
| 85 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 86 | + |
| 87 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 88 | + |
| 89 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 90 | + |
0 commit comments