⭐算法入门⭐《队列》简单02 —— LeetCode 346. 数据流中的移动平均值
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了⭐算法入门⭐《队列》简单02 —— LeetCode 346. 数据流中的移动平均值相关的知识,希望对你有一定的参考价值。
🙉饭不食,水不饮,题必须刷🙉
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
LeetCode 太难?先看简单题! 🧡《C语言入门100例》🧡
数据结构难?不存在的! 🌳《画解数据结构》🌳
LeetCode 太简单?算法学起来! 🌌《夜深人静写算法》🌌
一、题目
1、题目描述
给定一个整数数据流和一个窗口大小,根据该滑动窗口的大小,计算滑动窗口里所有数字的平均值。实现 MovingAverage 类:
MovingAverage(int size)
:用窗口大小 size 初始化对象。
double next(int val)
:成员函数 next 每次调用的时候都会往滑动窗口增加一个整数,请计算并返回数据流中最后 size 个值的移动平均值,即滑动窗口里所有数字的平均值。
样例输入:["MovingAverage", "next", "next", "next", "next"] [[3], [1], [10], [3], [5]]
样例输出:[null, 1.0, 5.5, 4.66667, 6.0]
2、基础框架
- C语言版本 给出的基础框架代码如下:
typedef struct {
} MovingAverage;
/** Initialize your data structure here. */
MovingAverage* movingAverageCreate(int size) {
}
double movingAverageNext(MovingAverage* obj, int val) {
}
void movingAverageFree(MovingAverage* obj) {
}
/**
* Your MovingAverage struct will be instantiated and called as such:
* MovingAverage* obj = movingAverageCreate(size);
* double param_1 = movingAverageNext(obj, val);
* movingAverageFree(obj);
*/
3、原题链接
( 1 ) (1) (1) LeetCode 346. 数据流中的移动平均值
( 2 ) (2) (2) 剑指 Offer II 041. 滑动窗口的平均值
二、解题报告
1、思路分析
- 把 滑动窗口 看成是队列里的元素,用一个 求和变量 来维护队列元素的和,这样就可以做到 O ( 1 ) O(1) O(1) 的求和,然后除上元素个数就是平均值了。
2、时间复杂度
- 两个指针都只增不减,所以总的时间复杂度为 O ( n ) O(n) O(n)。
3、代码详解
struct Data {
int val; //
};
/**************************** 链表 实现队列 ****************************/
#define DataType struct Data
#define maxn 100005
struct QueueNode;
struct QueueNode {
DataType data;
struct QueueNode *next;
};
struct Queue {
struct QueueNode *head, *tail;
int size;
};
void QueueEnqueue(struct Queue *que, DataType dt) {
struct QueueNode *insertNode = (struct QueueNode *) malloc( sizeof(struct QueueNode) );
insertNode->data = dt;
insertNode->next = NULL;
if(que->tail) {
que->tail->next = insertNode;
que->tail = insertNode;
}else {
que->head = que->tail = insertNode;
}
++que->size;
}
void QueueDequeue(struct Queue* que) {
struct QueueNode *delNode = que->head;
que->head = delNode->next;
free(delNode);
--que->size;
}
DataType QueueGetFront(struct Queue* que) {
return que->head->data;
}
int QueueGetSize(struct Queue* que) {
return que->size;
}
int QueueIsEmpty(struct Queue* que) {
return !QueueGetSize(que);
}
void QueueClear(struct Queue* que) {
que->head = que->tail = NULL;
que->size = 0;
}
/**************************** 链表 实现队列 ****************************/
typedef struct {
struct Queue q; // (1)
int size; // (2)
double sum; // (3)
} MovingAverage;
/** Initialize your data structure here. */
MovingAverage* movingAverageCreate(int size) { // (4)
MovingAverage *ret = (MovingAverage *)malloc(sizeof(MovingAverage));
QueueClear( &ret->q );
ret->size = size;
ret->sum = 0;
return ret;
}
double movingAverageNext(MovingAverage* obj, int val) {
struct Data dt;
dt.val = val;
struct Queue *q = &obj->q;
QueueEnqueue(q, dt); // (5)
obj->sum += val;
while(QueueGetSize(q) > obj->size) { // (6)
obj->sum -= QueueGetFront(q).val; // (7)
QueueDequeue(q);
}
return obj->sum / QueueGetSize(q); // (8)
}
void movingAverageFree(MovingAverage* obj) {
free(obj);
}
/**
* Your MovingAverage struct will be instantiated and called as such:
* MovingAverage* obj = movingAverageCreate(size);
* double param_1 = movingAverageNext(obj, val);
* movingAverageFree(obj);
*/
- ( 1 ) (1) (1) 用 队列 来记录这个窗口的 左右指针 ;
-
(
2
)
(2)
(2)
size
代表这个队列的最大长度; -
(
3
)
(3)
(3)
sum
代表队列中所有元素的和; - ( 4 ) (4) (4) 初始化滑动窗口;
- ( 5 ) (5) (5) 将新增数据流塞入队列,并且更新总和;
- ( 6 ) (6) (6) 如果滑动窗口的大小大于给定大小,则需要执行 出队 操作;
- ( 7 ) (7) (7) 出队 前,先将求和减去要出队的元素;
- ( 8 ) (8) (8) 总和 / 元素个数 就是平均值;
三、本题小知识
滑动窗口算法一般也叫双指针,也叫尺取法,名字有点多哈,但是思想是一样的,就是两个指针轮番向右滑动,这个归根结底还是 队列 的思想。
以上是关于⭐算法入门⭐《队列》简单02 —— LeetCode 346. 数据流中的移动平均值的主要内容,如果未能解决你的问题,请参考以下文章
⭐算法入门⭐《队列》简单02 —— LeetCode 346. 数据流中的移动平均值
⭐算法入门⭐《队列 - 单调队列》困难02 —— LeetCode1425. 带限制的子序列和