c语言求最大值_单调队列系列之1:队列的最大值 剑指 Offer 59 - II

请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。

若队列为空,pop_front 和 max_value 需要返回 -1

示例 1:

输入:

["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]

[[],[1],[2],[],[],[]]

输出: [null,null,null,2,1,2]

示例 2:

输入:

["MaxQueue","pop_front","max_value"]

[[],[],[]]

输出: [null,-1,-1]

限制:

1 <= push_back,pop_front,max_value的总操作数 <= 10000

1 <= value <= 10^5

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:题目要求均摊的时间复杂度是O(1),插入和删除操作都能做到O(1),困难在与求最大值的操作。使用线性查找,复杂度是O(n),不满足要求。

使用单调队列可以降低时间复杂度。

比如push的元素如下图所示。打个形象的比喻,将下面的元素比作一个并排站好的一列学生,数字大小表示对应位置上学生的身高,最左边是一面墙。大家在收到开始命令后一起向墙的方向进行推压,位于两个“高个”中间的“矮个”被挤压后,他们会因为无法忍受压力而被挤出队伍。这样就只剩下一排拍好队的“高个”。

264b77e4fa6f90b93ef25c5b5d536aa4.png

剩下的学生如下:

db8fefa10114405566af8a27db37ef7f.png

上图的过程就是一个单调队列(还细分为单调递增和单调递减)形成的过程,最大值是首元素。它的优势是可以做到O(1)的时间复杂度内返回最大值。

我们看看本题怎么实现这样的单调队列。首先创建双端队列 deque(c语言就是使用数组实现),这个双端队列用来保存上图中留下来的元素。在每次入队时,如果 deque 队尾元素小于即将入队的元素 value,则将小于 value 的元素全部出队后,再将 value 入队;否则直接入队。每次出队时,只需要判断出队的是不是deque的最多元素(首元素)即可,如果是,就pop掉当前首元素,如果不是,不需要做任何操作。当然还需要一个队列保存原始的数据,用来pop和push操作。

现在回答两个问题。

1. 上面蓝色条为什么可以被删除呢?

因为蓝色条两边存在两个比他们大的黄色条,无论删除到哪个元素,当前队列中最大元素都不会轮到它们,而是两边最大的黄色条之一。

比如上图中的5,7,3

删除到10元素时,最大元素是10

删除10后,最大元素是8

删除5,7,3时,最大元素还是8

删除8时,最大元素是下个黄色条7

所以5,7,3 是没有存在感的,可以忽略

2. 时间复杂度为什么是O(1)?

表面上需要使用while循环来将蓝色条一一剔除,但是它们只进来一次,出去一次,就两次,所以均摊的时间复杂度还是O(1)。

class MaxQueue {    queue q;    deque d;public:    MaxQueue() {    }        int max_value() {        if (d.empty())            return -1;        return d.front();    }        void push_back(int value) {        while (!d.empty() && d.back() < value) {            d.pop_back();        }        d.push_back(value);        q.push(value);    }        int pop_front() {        if (q.empty())            return -1;        int ans = q.front();        if (ans == d.front()) {            d.pop_front();        }        q.pop();        return ans;    }};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值