代码随想录(栈和队列)

目录

用栈实现队列(Leetcode232)

用队列实现栈(Leetcode225)

有效的括号(Leetcode20)

 删除字符串中的所有相邻重复项(Leetcode1047)

逆波兰表达式求值(Leetcode150)

 滑动窗口最大值(Leetcode239)

前K个高频的数(Leetcode347)


用栈实现队列(Leetcode232)

package 栈和队列;

import java.util.ArrayList;
import java.util.Stack;
思路:

1、用一个栈stack2来存压入的数,当要pop或peek操作时再压入stack中,实现队列顺序

2、不是每次pop都从stack2中压入数据,要stack中为空,也就是上一次压入的几个数pop完才可以再次压入新数据
public class 用栈实现队列 {
	
	public static void main(String[] args) {
		
	}
	
	//创建2个栈  stack1用来反转顺序辅助
	static Stack<Integer> stack;
	static Stack<Integer> stack2;

	    //先存在辅助栈中,比如 1 2 3 4 
	    public void push(int x) {
	    	stack2.push(x);
	    }
	    public int pop() {
	        if(stack.isEmpty()){  //要先判断stack是否有未输出完的数字  这里为什么需要stack为空,因为比如现在stack里面的是4321,pop一次后变成432 
	        					//这时push一次5 然后在pop 发现是输出5和队列不符 可以自己把判断stack为空的条件去掉验证一下,要将stack里面的数pop完才可以从stack2压新数
	            if(!stack2.isEmpty()) {  
	    		while(!stack2.isEmpty()) { //将之前的输入存入 这时候就是4321了 
	    			stack.push(stack2.pop());
	    		}
	    	    }
	        }
	    	return stack.pop(); //pop的就是1了
	    }
	    //和pop一样的道理
	    public int peek() {
	        if(stack.isEmpty()){
	            if(!stack2.isEmpty()) {
	                    while(!stack2.isEmpty()) {
	                        stack.push(stack2.pop());
	                    }
	                }
	        }
	    
			return stack.peek();
		}

		public boolean empty() {
			if (stack.empty() && stack2.empty()) {
				return true;
			} else {
				return false;
			}
		}

	}

用队列实现栈(Leetcode225)

//直接使用双向队列即可
class MyStack {
    static Deque<Integer> de;
    public MyStack() {
        this.de = new LinkedList<>();
    }
    
    
	public void push(int x) {
		de.add(x);
	}
	public int pop() {
		return de.pollLast();
	}
	public int top() {
		return de.peekLast();
	}
	public boolean empty() {
		return de.isEmpty();
	}
}

有效的括号(Leetcode20)

//思路
	//1、使用到了栈的思想
	//2、左括号入栈,遍历到右括号则从栈中弹出,看看是否匹配上
	//3、额外情况,左括号太多或者右括号太多
	public static  boolean isValid(String s) {
		Deque<Character> de = new LinkedList<>();
		for(int i = 0 ;i<s.length();i++) {
			char temp = s.charAt(i);
			if(temp=='('||temp=='{'||temp=='[') {
				de.addLast(temp);
			}else if(temp==')'||temp=='}'||temp==']') {
				//右括号多出来了
				if(de.isEmpty()) {
					return false;
				}
				if(temp==')'&&de.peekLast()=='(') {
					de.pollLast();
				}else if(temp=='}'&&de.peekLast()=='{') {
					de.pollLast();
				}else if(temp==']'&&de.peekLast()=='[') {
					de.pollLast();
				}else {
					return false;
				}
			}
		}
		//额外情况,左括号太多
		if(!de.isEmpty()) {
			return false;
		}else {
			return true;
		}
		
    }

 删除字符串中的所有相邻重复项(Leetcode1047)

思路,直接用栈思想即可,相邻且不同同或者栈为空则入栈,如果相同则把相同的数弹出
static Deque<Character> de = new LinkedList<>();
	public static String removeDuplicates(String s) {
		char[] arr = s.toCharArray();
		for(int i = 0;i<arr.length;i++) {
			if(de.isEmpty()||de.peekLast()!=arr[i]) {
				de.addLast(arr[i]);
			}else {
				de.pollLast();
			}
		}
		StringBuilder str = new StringBuilder();
		while(!de.isEmpty()) {
			str.append(de.pollFirst());
		}
		return new String(str);
	}

逆波兰表达式求值(Leetcode150)

思路:遇见数字就入栈,遇见运算符号就弹出2个进行运算后再入栈

注意:

1、因为输入的是字符串所以用Character.isDigit(tokens[i].charAt(0))来判断遍历到的是不是字符

2、由于可能存在“-123”这样的数,当纯用tokens[i].charAt(0)来判断可能会误判为减号,所以如果长度>1,直接入栈即可

3、运算时哪个在前哪个在后要注意,-和/是先出栈的在后
//遇见数字就入栈,预计运算字符就弹出两个进行运算 然后把运算后的再次入栈
	static Deque<String> de = new LinkedList<>();
	public static  int evalRPN(String[] tokens) {
		for(int i = 0;i<tokens.length;i++) {
			if(tokens[i].length()>1||Character.isDigit(tokens[i].charAt(0))){
				de.addLast(tokens[i]);
			}else {
				int a1 = Integer.parseInt(de.pollLast());
				int a2 = Integer.parseInt(de.pollLast());
				int temp=0;
				if(tokens[i].charAt(0)=='+') {
					temp = a1+a2;
				}else if(tokens[i].charAt(0)=='*') {
					temp= a1*a2;
				}else if(tokens[i].charAt(0)=='/') {
					temp = a2/a1; //注意
				}else if(tokens[i].charAt(0)=='-') {
					temp = a2-a1; //注意
				}
				de.addLast(String.valueOf(temp));
			}
		}
		
		return Integer.parseInt(de.peekLast());
    }

 滑动窗口最大值(Leetcode239)

思路:单调队列

1、如果遍历的数与队首的值相同时,队首出队

2、如果遍历到的数比队尾小,入队

3、如果遍历到的数比队尾大,则队尾出队直到队尾的数大于这个数为止,再把这个数入队
public int[] maxSlidingWindow(int[] nums, int k) {
		int len = nums.length - k + 1;
        //存放结果元素的数组
        int[] res = new int[len];
        int idx=0;
		Myque que = new Myque();
		for(int i = 0;i<k;i++) {
			que.push(nums[i]);
		}
		res[idx++]=que.peek_first();  //先存第一个区间的
		for(int i = k;i<nums.length;i++) {  //主要就是看区间第一个和最后一个数是否满足条件
			que.pop(nums[i-k]);   //区间头
			que.push(nums[i]);   //区间尾
			res[idx++] = que.peek_first();
		}
		return res;
	}

class Myque{
	private Deque<Integer> de;
	public Myque() {
		de = new LinkedList<>();
	}
	public void push(int value) {
		while(!de.isEmpty()&&de.peekLast()<value) { //判断队尾是否需要出队
			de.pollLast();
		}
		de.addLast(value);
	}
    
	public void pop(int value) {
		if(!de.isEmpty()&&de.peekFirst()==value) { //判断是否需要队首出队
			de.pollFirst();
		}
	}
	public int peek_first() {
		return de.peekFirst();
	}
}

前K个高频的数(Leetcode347)

//思路 用小顶堆思想
	//1、先用map计算每个元素的出现频率
	//2、重写java中使用PriorityQueue类实现堆,构造函数一般可传入两个参数(size,new Comparator())
	//①size:初始化堆的大小,若不传则默认为11,并且堆的大小会根据实际情况,自动扩展
	//②new Comparator():定义了堆排序的比较方式。默认排序为小顶堆,若要实现大顶堆,则需要重写Comparator类的compare方法(见大顶堆);
	//默认按自然排序,若要自定义排序方法,
	//3、遍历Key入队 
	public int[] topKFrequent(int[] nums, int k) {
		Map<Integer,Integer> map = new HashMap<>();
		for(int i = 0;i<nums.length;i++) {
			map.put(nums[i],(map.getOrDefault(nums[i], 0)+1));
		}
		PriorityQueue<Integer> pr = new PriorityQueue<>(k,new Comparator<Integer>() {
			@Override
			public int compare(Integer a,Integer b) {
				return map.get(a)-map.get(b);
			}
		});
		int size = 0;
		for(int j:map.keySet()) {
			if(size<k) { //前k个入队
				pr.offer(j);
				size++;
			}else if(map.get(pr.peek())<map.get(j)) { //比队首大,则队首出队 这个数入队
				pr.poll();
				pr.add(j);
			}
		}
		int[] res = new int[k];
		int idx = 0;
		while(!pr.isEmpty()) {
			res[idx++] = pr.poll();
		}
		return res;
		
    }

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值