队列、双向队列、栈 — ArrayDeque
- 使用双向队列ArrayDeque可以完成以上三种数据结构。队列的操作包括:入队、出队、返回队首元素、返回队尾元素、删除队首元素、删除队尾元素、判断空、返回队列长度。双向队列包括:首尾入队、首尾出队、返回首尾元素、删除首尾元素、判断空、返回队列长度。栈包括:入栈、出栈、返回栈顶元素、返回栈尾元素、判断空,返回栈长度。
双向队列:
-
addFirst(E e)
在此deque前面插入指定的元素。 -
addLast(E e)
在此deque的末尾插入指定的元素。 -
getFirst()
检索,但不删除,这个deque的第一个元素。 如果此deque为空,则报错。 -
getLast()
检索,但不删除,这个deque的最后一个元素。 如果此deque为空,则报错。 -
removeFirst()
检索并删除此deque的第一个元素。 如果此deque为空,则报错。 -
removeLast()
检索并删除此deque的最后一个元素。 如果此deque为空,则报错。 -
size()
返回此deque中的元素数。 -
contains(Object o)
如果此deque包含指定的元素,则返回 true 。 -
clear()
从这个deque中删除所有的元素。
@Test
public void my_queue(){
ArrayDeque<Integer> arrdeq = new ArrayDeque<>();
arrdeq.add(3);
arrdeq.add(9);
arrdeq.add(0);
arrdeq.addFirst(1);
arrdeq.addLast(2);
boolean con = arrdeq.contains(9);
Integer peekf = arrdeq.peekFirst(); //返回队头元素,如果此deque为空,则报错。
Integer peekl = arrdeq.peekLast();//返回队尾元素,如果此deque为空,则报错。
Integer pf = arrdeq.pollFirst();//队头元素出队并返回,如果此deque为空,则报错。
Integer pl = arrdeq.pollLast();//队尾元素出队并返回,如果此deque为空,则报错。
boolean empty = arrdeq.isEmpty();
arrdeq.clear();
}
- Note: 只要掌握了上面的双向队列的操作,那么栈和队列的操作也就会了。注意,最好使用如果队列为空报错的操作而不使用返回null的操作,因为,为空报错对于算法是好的,而返回null有时候很难发现错误!
堆(优先队列)— PriorityQueue
-
add(E e)
将指定的元素插入到此优先级队列中。 -
peek()
检索但不删除此队列的头,如果此队列为空,则返回 null 。 -
poll()
检索并删除此队列的头,如果此队列为空,则返回 null 。 -
remove(Object o)
从该队列中删除指定元素的单个实例(如果存在)。 -
size()
返回此集合中的元素数。 -
toArray()
返回一个包含此队列中所有元素的数组。 -
contains(Object o)
如果此队列包含指定的元素,则返回 true 。
@Test
public void my_priorityQueue(){
// 默认小根堆,如果要大根堆,只需要乘以-1即可,然后结果再恢复
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
pq.add(9);
pq.add(1);
pq.add(4);
Integer peek = pq.peek();
Integer poll = pq.poll();
boolean res = pq.remove(1);
}
232. 用栈实现队列
- 此题,使用基本栈实现队列,需要两个栈,一个为输入栈,当输入的时候按顺序入栈即可;另外一个为输出栈,需要把输入栈里的元素全部出栈到输出栈中,即倒置元素到输出栈中,如下图所示(图片来源:代码随想录);
import java.util.ArrayDeque;
public class MyQueue {
ArrayDeque<Integer> stack_in;
ArrayDeque<Integer> stack_out;
public MyQueue() {
stack_in = new ArrayDeque<>();
stack_out = new ArrayDeque<>();
}
public void push(int x) {
stack_in.addLast(x);
}
public int pop() {
// 如果输出栈还有元素,先用出栈
if(!stack_out.isEmpty()){
Integer p = stack_out.removeLast();
return p;
}
//else 否则
while (!stack_in.isEmpty()){
Integer last = stack_in.removeLast();
stack_out.addLast(last);
}
Integer p = stack_out.removeLast();
return p;
}
public int peek() {
// 如果输出栈还有元素,先用出栈
if(!stack_out.isEmpty()){
Integer p = stack_out.getLast();
return p;
}
//else 否则
while (!stack_in.isEmpty()){
Integer last = stack_in.removeLast();
stack_out.addLast(last);
}
Integer p = stack_out.getLast();
return p;
}
public boolean empty() {
if(stack_out.isEmpty() && stack_in.isEmpty()){
return true;
}
return false;
}
}
225. 用队列实现栈
思路,使用两个队列,当入队时,向非空的一个队列中入队,另外一个队列作为辅助队列用于存储挡在前面的元素。两个队列循环作为辅助队列使用,即空的那个即为辅助队列。注明:图片来源代码随想录!
import java.util.ArrayDeque;
public class MyStack {
ArrayDeque deque1;
ArrayDeque deque2;
public MyStack() {
deque1 = new ArrayDeque<Integer>();
deque2 = new ArrayDeque<Integer>();
}
public void push(int x) {
if(!deque1.isEmpty()){
deque1.addLast(x);
}else if(!deque2.isEmpty()){
deque2.addLast(x);
}else {
deque1.addLast(x);
}
}
public int pop() {
ArrayDeque<Integer> deque = null;
ArrayDeque<Integer> helpdeq = null;
if(!deque1.isEmpty()){
deque = deque1;
helpdeq = deque2;
}
if(!deque2.isEmpty()){
deque = deque2;
helpdeq = deque1;
}
while (deque.size()>1){
Integer value = deque.removeFirst();
helpdeq.addLast(value);
}
// 当deque.size()==1
Integer p = deque.removeFirst();
return p;
}
public int top() {
int pop = pop();
push(pop);
return pop;
}
public boolean empty() {
if(deque2.isEmpty() && deque1.isEmpty()){
return true;
}else {
return false;
}
}
}
LeetCode练习
-
20. 有效的括号
-
1047. 删除字符串中的所有相邻重复项
以上两题非常简单,直接套用栈就行。
-
150. 逆波兰表达式求值
思路:此题需要一个栈保存数字,当读取一个符号发现数值栈中大于两个数字则两个数字出栈进行运算后结果再入栈。
import java.util.ArrayDeque; public class lc150 { public boolean isNumber(String s){ if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")){ return false; }else { return true; } } public int evalRPN(String[] tokens) { ArrayDeque<Integer> stack = new ArrayDeque<>(); for (int i = 0; i < tokens.length; i++) { String s = tokens[i]; if(isNumber(s)){ int value = Integer.parseInt(s); stack.addLast(value); }else { if(stack.size()>=2){ int v2 = stack.removeLast(); int v1 = stack.removeLast(); switch (s){ case "+":{ stack.addLast(v1+v2); break; } case "-":{ stack.addLast(v1-v2); break; } case "*":{ stack.addLast(v1*v2); break; } case "/":{ stack.addLast(v1/v2); break; } } } } } return stack.getLast(); } }
347. 前 K 个高频元素
思路:先统计,再使用优先队列。
public int[] topKFrequent(int[] nums, int k) {
TreeMap<Integer, Integer> map = new TreeMap<>();
PriorityQueue<Map.Entry<Integer, Integer>> pq = new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o2.getValue()-o1.getValue();
}
});
for(int a: nums){
// map.put(num,map.getOrDefault(num,0)+1);
if(map.containsKey(a)){
map.replace(a,map.get(a)+1);
}else {
map.put(a,1);
}
}
Set<Map.Entry<Integer, Integer>> entries = map.entrySet(); //转为集合
ArrayList<Map.Entry<Integer, Integer>> arr = new ArrayList<>(entries); //转为数组
for (int i = 0; i < arr.size(); i++) {
pq.add(arr.get(i));
}
// Collections.sort(arr, new Comparator<Map.Entry<Integer, Integer>>() {
// @Override
// public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
// return o1.getValue()-o2.getValue();
// }
// });
int[] res = new int[k];
for (int i = 0; i < k; i++) {
Map.Entry<Integer, Integer> poll = pq.poll();
res[i] = poll.getKey();
}
return res;
}
735. 行星碰撞
public int[] asteroidCollision(int[] asteroids) {
ArrayDeque<Integer> stack = new ArrayDeque<>();
for(int a : asteroids){
if(stack.isEmpty() || (stack.getLast()<0 && a>0) || stack.getLast()*a>0){
// 如果栈为空,或者<-- -->这样的方向,或者同向,直接加进来,因为这些都喷不到
stack.addLast(a);
}else {
while(!stack.isEmpty() && (stack.getLast()>0 && a<0) && Math.abs(stack.getLast())<Math.abs(a)){
stack.pollLast();
}
//因为空结束,同向结束
if(stack.isEmpty()||stack.getLast()*a>0){
stack.addLast(a);
}
//因为质量相等结束,条件要求会碰才能消除
else if(Math.abs(stack.getLast())==Math.abs(a) && (stack.getLast()>0 && a<0)){
stack.pollLast();
}
}
}
int[] res = new int[stack.size()];
int i=0;
while (!stack.isEmpty()){
res[i] = stack.pollFirst();
i++;
}
return res;
}
739. 每日温度
public int[] dailyTemperatures(int[] temperatures) {
// 单调栈,维护一个递减栈
ArrayDeque<int[]> stack = new ArrayDeque<>();
int[] res = new int[temperatures.length];
int[][] temp = new int[temperatures.length][2];
for (int i = 0; i < temperatures.length; i++) {
temp[i][0] = i; //第一个记录下标
temp[i][1] = temperatures[i]; //第二个记录下标对应的温度
}
stack.addLast(temp[0]);
for (int i = 1; i < temp.length; i++) {
int[] ct = temp[i]; //现在的温度
while (!stack.isEmpty()){
if(ct[1]>stack.getLast()[1]){
int[] last = stack.pollLast();
res[last[0]] = i-last[0]; //出栈:第一个比它大的下标-他自己的下标 就是第几天温度比他高
}else {
stack.addLast(ct);
break;
}
}
// 否则栈空就进栈
stack.addLast(ct);
}
return res;
}