代码随想录自刷6:栈与队列

109 阅读2分钟

先明白栈和队列的区别。

  • 栈:先进后出(想成一个桶子,最先放进去的东西被压在底下,需要等它上面的东西拿完才能拿它)
    • 提供:push/pop接口等
  • 队列:先进先出(排队,排在第一个位置的人,可以先走)
    • 提供:add/poll接口等等

232. 用栈实现队列

232. 用栈实现队列

思路:重点要画图理解!使用两个栈来实现,一开始两个都为空

  • push方法:始终交给一个栈s1处理插入
  • pop方法:因为现在弹出的顺序是按照先进后出的!所以不符合要求,需要处理一下
    • 只要把s1中的元素全部放到s2中,此时s2弹出来的元素顺序其实就跟队列一样了!
    • 当s2中的元素都没了,就要继续从s1中把累积的元素放到s2!
    • 总结:最后的弹出交给s2处理!
  • peek方法:同理pop方法
class MyQueue {
    Stack<Integer> s1;
    Stack<Integer> s2;
    public MyQueue() {
        s1=new Stack<>();
        s2=new Stack<>();
    }
    
    public void push(int x) {   
        s1.push(x);
    }
    
    public int pop() {
        if(s2.isEmpty()){
            while(!s1.isEmpty()){
                s2.push(s1.pop());
            }
        }
        int val=s2.pop();
        return val;
    }
    
    public int peek() {
        if(s2.isEmpty()){
            while(!s1.isEmpty()){
                s2.push(s1.pop());
            }
        }
        int val=s2.peek();
        return val;
    }
    
    public boolean empty() {
        return s1.isEmpty()&&s2.isEmpty();
    }
}

225. 用队列实现栈

225. 用队列实现栈

思路:跟上面题目类似,但现在是用队列实现栈,依旧需要两个队列。

  • push方法:记住最后q2始终为空!最终元素都在q1。那如何加入元素?首先加入到q2中,然后将q1队列都放到q2中。这样弹出顺序就是跟栈是一致的。最后交换两个队列。(保持固定这样下次就不用判断哪个队列为空?要插入哪个队列...等等)
  • pop方法:元素都在q1,所以直接操作q1弹出
  • top方法:同pop方法
class MyStack {
    Queue<Integer> q1;
    Queue<Integer> q2;
    public MyStack() {
        q1=new LinkedList<>();
        q2=new LinkedList<>();
    }
    //最后q2始终为空!最终元素都在q1
    public void push(int x) {
        q2.add(x);
        while(!q1.isEmpty()){
            q2.add(q1.poll());
        }
        Queue<Integer> temp=q1;
        q1=q2;
        q2=temp;
    }
    
    public int pop() {
       return q1.poll();
    }
    
    public int top() {
        return q1.peek();
    }
    
    public boolean empty() {
        return q1.isEmpty();
    }
}

20. 有效的括号

20. 有效的括号

思路:利用stack的先进后出特性,如果遇到左括号则放入对应的右括号。当前字符串如果是右括号,则跟stack中的元素进行比对,如果相同表示凑成一对!不同表示不能凑对是无用的返回false

public boolean isValid(String s) {
        Stack<Character> stack=new Stack<>();
        for(char ch : s.toCharArray()){
            if(ch=='('){
                stack.push(')');
            }
            else if(ch=='['){
                stack.push(']');
            }else if(ch=='{'){
                stack.push('}');
            }else{
                if(!stack.isEmpty() && stack.peek()==ch)
                    stack.pop();
                else    
                    return false;
            }
        }
        return stack.isEmpty();
    }

1047. 删除字符串中的所有相邻重复项

1047. 删除字符串中的所有相邻重复项

思路:⚠️用的是if!而不是while!如果当前元素和stack中元素相同,于是把stack中元素删除,并且当前元素不会加到stack中(等于同时删除两个,不会加到stack中)。stack中剩余的元素等下次遍历时继续判断是有相同还是没有相同

 public String removeDuplicates(String s) {
        Stack<Character> stack=new Stack<>();
        for(char ch :s.toCharArray()){
            if(!stack.isEmpty() && stack.peek()==ch){
                stack.pop();
            }
            else
                stack.push(ch);
        }
         String str=new String();
        while(!stack.isEmpty()){
            str=stack.pop()+str;
        }
        return str;
    }

150. 逆波兰表达式求值

150. 逆波兰表达式求值

思路:也是用stack的特性,根据逆波兰表示法,遇到运算符时,肯定已经有2个数字(or以上),放心取出来

public int evalRPN(String[] tokens) {
        Stack<Integer> stack=new Stack<>();
        for(int i=0;i<tokens.length;i++){
            if(tokens[i].equals("+")){
                int b=stack.pop();
                int a=stack.pop();
                stack.push(a+b);
            }else if(tokens[i].equals("-")){
                int b=stack.pop();
                int a=stack.pop();
                stack.push(a-b);
            }else if(tokens[i].equals("*")){
                int b=stack.pop();
                int a=stack.pop();
                stack.push(a*b);
            }else if(tokens[i].equals("/")){
                int b=stack.pop();
                int a=stack.pop();
                stack.push(a/b);
            }else
            stack.push(Integer.valueOf(tokens[i]));
        }
        return stack.peek();
    }

239. 滑动窗口最大值

239. 滑动窗口最大值

思路:滑动窗口在遍历数组时,顺带找出当前滑动窗口范围内最大的元素!用双端队列作为滑动窗口!要注意:

  • 队列中元素要排序(单调递减)
  • 头部放最大的元素
  • 窗口移动的时候,队列需要弹出超过窗口范围的元素

没有现成的,需要我们自己去实现一下这个队列!

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        myQueue queue=new myQueue();
        int[] res=new int[nums.length-k+1];
        for(int i=0;i<k;i++){
            queue.add(nums[i]);
        }
        //第一个范围
        int idx=0;
        res[idx++]=queue.peek();
        for(int i=k;i<nums.length;i++){
            //窗口移动,弹出超出范围的元素
            queue.poll(nums[i-k]);
            //加入可能的最大元素
            queue.add(nums[i]);
            res[idx++]=queue.peek();
            //窗口继续往下移动
        }
        return res;
    }
    class myQueue{
        Deque<Integer> queue;
        public myQueue(){
            queue=new LinkedList<>();
        }

        public void add(int val){
            while(!queue.isEmpty() && queue.getLast()<val){
                queue.removeLast();
            }
            queue.add(val);
        }
        
        public void poll(int val){
            if(!queue.isEmpty() && queue.peek()==val){
                queue.poll();
            }
        }
        public int peek(){
            return queue.peek();
        }
    }
}

思路:

347. 前 K 个高频元素

347. 前 K 个高频元素

思路:使用优先级队列,先用map记录每个数的次数,然后将map的entry集合放入到set中!创建一个优先级队列,遍历set中的entry,一个个加入队列中,如果当前队列大小超过k表示要剔除元素,于是把头部元素丢掉(队列是先先进先出),头部元素正好就是当前元素中次数最小的那个。遍历结束就得到前k个高频元素!再放到数组中

public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer> map=new HashMap<>();
        for(int i:nums){
            map.put(i,map.getOrDefault(i,0)+1);
        }
        Set<Map.Entry<Integer,Integer>> set=map.entrySet();
        //次数是小到大的优先队列
        PriorityQueue<Map.Entry<Integer,Integer>> queue=new PriorityQueue<>((a,b)->a.getValue()-b.getValue());
        for(Map.Entry<Integer,Integer> entry :set){
            queue.add(entry);
            //超过size,就弹出头部元素(当前队列中次数最小的)
            if(queue.size()>k){
                queue.poll();
            }
        }
        int[] res=new int[k];
        int idx=0;
        while(!queue.isEmpty()){
            res[idx++]=queue.poll().getKey();
        }
        return res;
    }