一、知识
队列这个概念非常好理解。你可以把它想象成排队买票,先来的先买,后来的人只能站末尾,不允许插队。先进者先出,这就是典型的“队列”。
队列跟栈一样,也是一种操作受限的线性表数据结构 。队列最基本的操作也是两个:入队:放一个数据到队列尾部;出队:从队列头部取一个元素。用数组实现的队列叫作顺序队列,用链表实现的队列叫作链式队列。
项目中用到的特殊队列:阻塞队列、并发队列等。(阻塞队列就是入队、出队操作可以阻塞,并发队列就是队列的操作多线程安全)
二、应用
可以通过数组、链表实现循环双端队列,下面方法通过数组实现,需要注意的点为:头尾指针变动需要进行特殊处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| class MyCircularDeque {
private int[] arr; private int start; private int end; private int size;
public MyCircularDeque(int k) { arr = new int[k + 1]; size = k + 1; start = 0; end = 0; }
public boolean insertFront(int value) { if (isFull()) { return false; } start = (start - 1 + size) % size; arr[start] = value; return true; }
public boolean insertLast(int value) { if (isFull()) { return false; } arr[end] = value; end = (end + 1) % size; return true; }
public boolean deleteFront() { if (isEmpty()) { return false; } start = (start + 1) % size; return true; }
public boolean deleteLast() { if (isEmpty()) { return false; } end = (end - 1 + size) % size; return true; }
public int getFront() { if (isEmpty()) { return -1; } return arr[start]; }
public int getRear() { if (isEmpty()) { return -1; } return arr[(end - 1 + size) % size]; }
public boolean isEmpty() { return end == start; }
public boolean isFull() { return (end + 1) % size == start; } }
|
双端队列存储长为 k 的滑动窗口的下标,为什么存下标:判断该数是否在窗口中。将元素存入双端队列时,应将该元素与队列中最后的元素进行判断,小于则弹出最后的元素,直至队列中元素大于等于该元素或者队列为空,这样队首元素即为当前窗口的最大元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public int[] maxSlidingWindow(int[] nums, int k) { Deque<Integer> deque = new ArrayDeque(); for (int i = 0; i < k; i++) { while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) { deque.pollLast(); } deque.offerLast(i); } int[] arr = new int[nums.length - k + 1]; arr[0] = nums[deque.peekFirst()]; for (int i = k; i < nums.length; i++) { if (deque.peek() + k - 1 < i) { deque.poll(); } while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) { deque.pollLast(); } deque.offerLast(i); arr[i - k + 1] = nums[deque.peekFirst()]; } return arr; }
|
创建两个队列,一个为双端队列用于存储最大值(方法和第二题一样),需要出队时判断普通队列和双端队列的队首的值是否一样,一样则出队。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class MaxQueue { private Deque<Integer> deque; private Deque<Integer> maxDeque;
public MaxQueue() { deque = new ArrayDeque(); maxDeque = new ArrayDeque(); }
public int max_value() { if (maxDeque.isEmpty()) { return -1; } return maxDeque.peek(); }
public void push_back(int value) { while (!maxDeque.isEmpty() && maxDeque.peekLast() < value) { maxDeque.pollLast(); } deque.offerLast(value); maxDeque.offerLast(value); }
public int pop_front() { if (deque.isEmpty()) { return -1; } if (deque.peek().equals(maxDeque.peek())) { maxDeque.poll(); } return deque.poll(); } }
|