【Sliding Window】B000_队列的最大值(滑动窗口)

一、题目描述

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

输入: 
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]

二、题解

方法一:数组模拟队列

思路

  • head,rear 维护一个窗口。
  • max_value():当数组 queue 不空,max 自然会被赋值为大于 1 的数,所以在 isEmpty() 中无需判断。
  • pop_front()
    • 当数组为空,返回 -1。
    • 当数组非空,且队头元素 queue[front] == max 时,“弹出” 之前需要对 max 重新寻找最大值。
class MaxQueue {
  private int[] queue;
  private int head;
  private int rear;
  private int max;
  public MaxQueue() {
    queue = new int[10006];
    head = 0;
    rear = 0;
    max = -1;
  }

  private boolean isEmpty() {
    return head == rear;
  }

  public int max_value() {
    return max;
  }

  public void push_back(int value) {
    queue[rear++] = value;
    if (value > max)
      max = value;
  }

  public int pop_front() {
    if (isEmpty())  return -1;
    //如果队头元素和max相等,那么需要对max的值作出改变:
    if (queue[head] == max) {
      max = -1;
      for (int i = head + 1; i < rear; i++) {
        if (queue[i] > max)
          max = queue[i];
      }
    }
    return queue[head++];
  }
}

复杂度分析

  • 时间复杂度:
    • 弹出 O ( n ) O(n)

    • 压入 O ( 1 ) O(1)

方法二:双端队列

保证 sort_que 内部的元素是单调递减的,每次添加元素的时候,sort_que 需要对队尾元素进行判断,如果队尾元素比即将加入队列的 value 要小,那么我们认为队尾的元素是无用的,因为我们要在 max_value 返回最大值。

  • 当队列为空,返回 -1。
  • 当队列非空,且队头元素 queue.poll() == sort_que.peek() 时,则直接把 sort_que 的队头元素(最大值)弹出。
class MaxQueue {
  ArrayDeque<Integer> queue;
  ArrayDeque<Integer> sort_que;
  public MaxQueue() {
    queue = new ArrayDeque<>();
    sort_que = new ArrayDeque<>();
  }

  public int max_value() {
    return queue.isEmpty() ? -1 : sort_que.peek();
  }

  public void push_back(int value) {
    queue.add(value);
    // 让队列的元素单调递减
    while (!sort_que.isEmpty() && value > sort_que.peekLast()) {
      sort_que.pollLast();
    }
    sort_que.add(value);
  }

  public int pop_front() {
    if (queue.isEmpty())
      return -1;
    int front = queue.poll();
    if (front == sort_que.peek()) { //只弹出一个元素
      sort_que.poll();
    }
    return front;
  }
}

复杂度分析

  • 时间复杂度: O ( 1 ) O(1) ;总的来看,每个元素在队列中,最多不过进入 add 一次和 poll 出队列一次,因此维护队列的最大代价不过是 O(2n)(每个元素都进入一次,再出来一次),而这 O(2n) 是在 n 个循环里面完成的,那么一次操作的时间复杂度为 O(2) = O(1)
  • 空间复杂度: O ( n ) O(n)
发布了461 篇原创文章 · 获赞 102 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104709474