题目链接

LeetCode

题目描述

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

示例

  1. 示例 1
  2. 输入:
  3. ["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
  4. [[],[1],[2],[],[],[]]
  5. 输出: [null,null,null,2,1,2]
  6. 示例 2
  7. 输入:
  8. ["MaxQueue","pop_front","max_value"]
  9. [[],[],[]]
  10. 输出: [null,-1,-1]

解题思路

方法一:暴力方法

算法步骤如下:

  • 枚举每个窗口的左边界 i
  • 根据窗口的左边界i可以对应计算出右边界j
  • 遍历窗口,计算出最大值 ```cpp class MaxQueue { public: vector v; MaxQueue() {

    }

    int max_value() {

    1. if(v.empty())
    2. return -1;
    3. int max = v[0];
    4. for(int i = 0;i<v.size();++i){
    5. if(v[i]>max)
    6. max = v[i];
    7. }
    8. return max;

    }

    void push_back(int value) {

      v.push_back(value);
    

    }

    int pop_front() {

      if(v.empty()){
          return -1;
      }
      int ret  = v[0];
      v.erase(v.begin());
      return ret;
    

    } };

/**

  • Your MaxQueue object will be instantiated and called as such:
  • MaxQueue* obj = new MaxQueue();
  • int param_1 = obj->max_value();
  • obj->push_back(value);
  • int param_3 = obj->pop_front(); */ ```
  • 时间复杂度:O(1)(插入,删除),O(n)(求最大值)。插入与删除只需要普通的队列操作,为 O(1),求最大值需要遍历当前的整个队列,最坏情况下为 O(n))。
  • 空间复杂度:O(n)需要用队列存储所有插入的元素。

方法二:单调队列

为了解决上述问题,我们只需记住当前最大值出队后,队列里的下一个最大值即可。

具体方法是使用一个双端队列 deque,在每次入队时,如果 deque 队尾元素小于即将入队的元素 value,则将小于 value 的元素全部出队后,再将 value 入队;否则直接入队。
这时,辅助队列 deque 队首元素就是队列的最大值。

59.2 队列的最大值* - 图1

class MaxQueue {
public:
    queue<int> q;
    deque<int> dq;
    MaxQueue() {

    }

    int max_value() {
        if(dq.empty())
            return -1;
        return dq.front();
    }

    void push_back(int value) {
        q.push(value);
        while(!dq.empty()&&dq.back()<value)
            dq.pop_back();
        dq.push_back(value);
    }

    int pop_front() {
        if(q.empty())
            return -1;
        int ret = q.front();
        q.pop();
        if(ret==dq.front())
            dq.pop_front();
        return ret;
    }
};

/**
 * Your MaxQueue object will be instantiated and called as such:
 * MaxQueue* obj = new MaxQueue();
 * int param_1 = obj->max_value();
 * obj->push_back(value);
 * int param_3 = obj->pop_front();
 */
class MaxQueue {
    private Deque<Integer> queue, stack;
    public MaxQueue() {
        queue = new LinkedList<Integer>();
        stack = new LinkedList<Integer>();
    }

    public int max_value() {
        return stack.isEmpty() ? -1 : stack.peekFirst();
    }

    public void push_back(int value) {
        queue.offerLast(value);
        while(!stack.isEmpty() && stack.peekLast() < value){
            stack.pollLast();
        }
        stack.offerLast(value);
    }

    public int pop_front() {
        if(queue.isEmpty()){
            return -1;
        }
        int res = queue.pollFirst();
        if(!stack.isEmpty() && res == stack.peekFirst()){
            stack.pollFirst();
        }
        return res;
    }
}

/**
 * Your MaxQueue object will be instantiated and called as such:
 * MaxQueue obj = new MaxQueue();
 * int param_1 = obj.max_value();
 * obj.push_back(value);
 * int param_3 = obj.pop_front();
 */

时间复杂度

  • max_value:O(1),直接返回双端队列(或数组)头部的元素。
  • pop_front:O(1),从队列中弹出一个元素,仍然是常数时间复杂度。
  • push_back:O(1),例如 543216,只有最后一次 push_back 操作是O(n),其他每次操作的时间复杂度都是 O(1),均摊时间复杂度为(O(1)×(n−1)+O(n))/n=O(1)。