1 什么是队列
队列是一种特殊的线性表,限定只能在线性表的一端进行插入(队尾),而在另一端进行删除操作(对头),特点是先进先出(FIFO)。
public static void main(String[] args) {
Queue<Integer> queue=new LinkedList<>();
//添加一个元素
queue.add(1);
//返回队列头元素(不删除),队列为空返回null
System.out.println(queue.peek());
//返回队列头元素并移除,队列为空返回null
System.out.println(queue.poll());
System.out.println(queue.poll());
}
}
数组实现队列,核心有head 和tail 两个指针控制。
public class MyQueue<T> {
private Object[] element;
private int head;
private int tail;
public MyQueue() {
this.element = new Object[16];
head = 0;
tail = 0;
}
public void add(T e) {
element[tail] = e;
tail++;
//如果等于头部,则扩容,这里面使用&代替求余,扩容容量必须是2整数倍
if ((tail & (element.length - 1)) == head) {
resize();
}
}
private void resize() {
int newCapacity = element.length << 1;
int p = head;
int n = element.length;
if (newCapacity < 0) {
throw new IllegalStateException("Sorry, deque too big");
}
Object[] newElement = new Object[newCapacity];
System.arraycopy(element, p, newElement, 0, n - p);
System.arraycopy(element, 0, newElement, n - p, p);
element = newElement;
head = 0;
tail = n;
}
public boolean isEmpty() {
return head == tail;
}
public T peek() {
return (T) element[head];
}
public T poll() {
if (isEmpty()) {
return null;
}
T e = (T) element[head];
element[head] = null;
head = (head + 1) & (element.length - 1);
return e;
}
public int size() {
return (tail - head) & (element.length - 1);
}
public static void main(String[] args) {
MyQueue<Integer> myQueue=new MyQueue<>();
for(int i=0;i<32;i++) {
myQueue.add(i);
}
for(int i=0;i<35;i++) {
System.out.println(myQueue.poll());
}
}
}
双端队列是两端都可以进行插入和移除操作的队列。
Deque<Integer> queue=new ArrayDeque<>();
//添加一个元素
queue.addFirst(1);
queue.addLast(1);
System.out.println(queue.peekLast());
System.out.println(queue.peekFirst());
优先级队列是数据项按照关键字排好的顺序的队列,正常入按照优先级出,其排序是动态的变化的。实现机制:Heap(Binary-二叉队,Binomial-多项式,FIbonacci),Binary-Search Tree 二叉搜索树。在算法设计经常从序列找一个最值(最大值或者最小值)。
2 实战,用队列实现栈
https://leetcode-cn.com/problems/implement-stack-using-queues/
思路:用两个队列 first和second,在push数据,先加入first队列,然后把second 数据,加入first队列,然后交换first和second队列,这样可以保证最后数据在队列头。
class MyStack {
private Queue<Integer> first=null;
private Queue<Integer> second=null;
public MyStack() {
first=new ArrayDeque<>();
second=new ArrayDeque<>();
}
public void push(int x) {
first.add(x);
while(!second.isEmpty()){
first.add(second.poll());
}
Queue<Integer> tmp=first;
first=second;
second=tmp;
}
public int pop() {
if(second.isEmpty()){
return -1;
}
return second.poll();
}
public int top() {
if(second.isEmpty()){
return -1;
}
return second.peek();
}
public boolean empty() {
return second.isEmpty();
}
}
3 实战滑动窗口最大值
https://leetcode-cn.com/problems/sliding-window-maximum/
思路:两层循序,找最大元素
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums==null || nums.length<=1) {
return nums;
}
int len=nums.length;
int[] res=new int[len-k+1];
for(int i=0;i<=len-k;i++){
int max=nums[i];
for(int j=i+1;j<k+i;j++) {
if(max<nums[j]){
max=nums[j];
}
}
res[i]=max;
}
return res;
}
}
思路:使用优先队列,要检查队列中元素是否满足条件
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums==null || nums.length<=1) {
return nums;
}
int len=nums.length;
int[] res=new int[len-k+1];
PriorityQueue<Pos> queue=new PriorityQueue<>();
for(int i=0;i<k-1;i++) {
queue.offer(new Pos(nums[i],i));
}
for(int i=k-1;i<len;i++){
queue.offer(new Pos(nums[i],i));
//判断下标位置是否满足条件
while(queue.peek().index<=i-k){
queue.poll();
}
res[i-k+1]=queue.peek().value;
}
return res;
}
public static class Pos implements Comparable<Pos> {
public Integer value;
public Integer index;
public Pos(int val,int index) {
this.value=val;
this.index=index;
}
@Override
public int compareTo(Pos pos){
return pos.value.compareTo(value);
}
}
}
4. 数据流中的第 K 大元素
https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/
思路:保留最大K值数组,时间复杂度是n*klogk
class KthLargest {
private List<Integer> kList=null;
private int k=0;
public KthLargest(int k, int[] nums) {
kList=new ArrayList<>();
this.k=k;
for(int i=0;i<nums.length;i++){
add(nums[i]);
}
}
public int add(int val) {
if(kList.size()<k) {
kList.add(val);
Collections.sort(kList);
return kList.get(0);
}
//最小值
if(kList.get(0)>val) {
return kList.get(0);
}else {
kList.remove(0);
kList.add(val);
Collections.sort(kList);
}
return kList.get(0);
}
}
思路:利用堆思想,使用优先队列
class KthLargest {
private Queue<Integer> queue=null;
private int k=0;
public KthLargest(int k, int[] nums) {
queue=new PriorityQueue<>();
this.k=k;
for(int i=0;i<nums.length;i++){
add(nums[i]);
}
}
public int add(int val) {
queue.add(val);
if(queue.size()>k){
queue.poll();
}
return queue.peek();
}
}