⭐算法入门⭐《队列》简单02 —— LeetCode 346. 数据流中的移动平均值

🙉饭不食,水不饮,题必须刷🙉

C语言免费动漫教程,和我一起打卡!
🌞《光天化日学C语言》🌞

LeetCode 太难?先看简单题!
🧡《C语言入门100例》🧡

数据结构难?不存在的!
🌳《画解数据结构》🌳

闭关刷 LeetCode,剑指大厂Offer!
🌌《LeetCode 刷题指引》🌌

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) 总和 / 元素个数 就是平均值;

三、本题小知识

   滑动窗口算法一般也叫双指针,也叫尺取法,名字有点多哈,但是思想是一样的,就是两个指针轮番向右滑动,这个归根结底还是 队列 的思想。


  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值