栈stack 和 队列queue, 本质是List()+适用问题

容器适配器:队列Queue:先进出;栈Stack:先进后出;双向队列Deque

多种情况是可以用:switch-case 判断效率比 if-else 更高

底层实现:ArrayList[] 比 LinkedList[] 实现队、栈的效率更高,默认为Deque(LinkedList[])

1. 用栈实现队

2. 用队实现栈

3. 利用栈stack判断对称匹配问题

4. 计算后缀表达式 eg:3,4,+,

5、单调队列:滑动窗口 Deque  pollFirst(),pollLast(),peakFirst(),peskLast()

6、优先级队列:= 小顶堆、大顶堆


1. 用栈实现队

232. 用栈实现队列:以队列出队的元素顺序出栈,将栈中元素依次copy到另一栈中,在pop

//用两个栈实现队列的功能
class MyQueue {
    //属性:两个栈
    Stack<Integer> stackIn;
    Stack<Integer> stackOut;
    //构造器:初始化
    public MyQueue() {
        stackIn = new Stack();
        stackOut = new Stack();
    }
    
    public void push(int x) {
        stackIn.push(x);
    }
    
    public int pop() {
        popTostackOut();
        return stackOut.pop();
    }
    
    public int peek() {
        popTostackOut();
        return stackOut.peek();
    }
    
    public boolean empty() {
        if(stackOut.isEmpty() && stackIn.isEmpty()){
            return true;
        }
        return false;
    }

    public void popTostackOut(){
        if(!stackOut.isEmpty()){
            return;
        }
        while(!stackIn.isEmpty()){
            stackOut.push(stackIn.pop());
        }
    }
}

2. 用队实现栈

225. 用队列实现栈:分别利用一个队列、两个队列实现栈功能:每次以出栈的顺序添加到队列中

//java 中队列用Queue或Deque   通用方法:size(),idEmpty()
//其中:Queue 中的 add进、poll出、peek队头元素值 等效于 Deque 中的 addLast、pollFirst、peekFirst
class MyStack {
    Queue<Integer> q1;
    Queue<Integer> q2;
    public MyStack() {
        q1 = new LinkedList<>();
        q2 = new LinkedList<>();
    }
    //按照栈的顺序加入队列中
    public void push(int x) {
        //利用两个队列
        q2.add(x);
        while(!q1.isEmpty()){
            q2.add(q1.poll());
        }
        Queue<Integer> temp = q1;
        q1 = q2;
        q2 = temp;//q2每次结束是为空
        
        // //利用一个队列
        // int len = q1.size();
        // q1.add(x);
        // while(len-- > 0){
        //     q1.add(q1.poll());
        // }
    }
    
    public int pop() {
        return q1.poll();
    }
    
    public int top() {
        return q1.peek();
    }
    
    public boolean empty() {
        return q1.isEmpty();
    }
}

3. 利用stack判断对称匹配问题

20. 有效的括号:判断数据是否为对称匹配类的题目,多使用栈stack来解决。如果相同的话 栈就弹出

//判断数据是否为对称匹配类的题目,多使用栈来解决
class Solution {
    public boolean isValid(String s) {
        if(s.length()%2 != 0){ //相当于剪枝操作,避免多余步骤
            return false;
        }
        Stack<Character> stack = new Stack<>();
        int i = 0;
        for(; i< s.length(); i++){
            char ch = s.charAt(i);
            if(ch == '('){
                stack.push(')');
                continue;
            }
            if(ch == '['){
                stack.push(']');
                continue;
            }
            if(ch == '{'){
                stack.push('}');
                continue;
            }
            if(stack.isEmpty() || ch != stack.peek()){
                break;
            }else{
                stack.pop();
            }
        }
        return (i == s.length() && stack.isEmpty());//完全匹配的条件:字符串遍历结束且栈为空
    }
}

1047. 删除字符串中的所有相邻重复项:  相邻重复项即对称项,可用栈解决;或者数组快慢双指针

//使用堆栈解决对称问题
// class Solution {
//     public String removeDuplicates(String s) {
//         Stack<Character> stack = new Stack<>();
//         for(int i = 0; i < s.length(); i++){
//             char ch = s.charAt(i);
//             if(stack.isEmpty() || ch != stack.peek()){
//                 stack.push(ch);
//             }else{
//                 stack.pop();
//             }
//         }
//         int len = stack.size();
//         char[] slast = new char[len];
//         while(!stack.isEmpty()){
//             slast[--len] = stack.pop();
//         }

//         return new String(slast);
//     }
// }

//直接判断
class Solution {
    public String removeDuplicates(String s) {
        StringBuilder slast = new StringBuilder();
        int len = 0;
        for(int i = 0; i < s.length(); i++){
            char ch = s.charAt(i);
            if(len == 0 || ch != slast.charAt(len-1)){
                slast.append(ch);
                len++;
            }else{
                slast.deleteCharAt(len-1);
                len--;
            }
        }
        return slast.toString();
    }
}

4. 计算后缀表达式 eg:3,4,+,

// // 逆波兰表示法=后缀表达式法
// class Solution {
//     public int evalRPN(String[] tokens) {
//         Stack<Integer> res = new Stack<>();
//         for(int i=0; i < tokens.length; i++){
//             String s = tokens[i];
//             //注意: 比较字符串内容是否相等为equals()
//             if(s.equals("+")){
//                 res.push(res.pop()+res.pop());
//             }else if(s.equals("-")){
//                 res.push(-res.pop()+res.pop());
//             }else if(s.equals("*")){
//                 res.push(res.pop()*res.pop());
//             }else if(s.equals("/")){
//                 int a = res.pop();
//                 int b = res.pop();
//                 res.push(b/a);
//             }else{
//                 res.push(Integer.parseInt(s));
//             }
//         }
//         return res.pop();
//     }
// }
//用数组创建栈,多种情况判断用switch-case
class Solution {
    public int evalRPN(String[] tokens) {
        int[] stack = new int[tokens.length];
        int index = -1;
        int num;
        for(String s:tokens){
            switch(s){
                case "+": num = stack[index];
                          index--;
                          stack[index] += num;
                          continue;
                case "-": num = stack[index];
                          index--;
                          stack[index] -= num;
                          continue;
                case "*": num = stack[index];
                          index--;
                          stack[index] *= num;
                          continue;
                case "/": num = stack[index];
                          index--;
                          stack[index] /= num;
                          continue;
                default:  index++;
                          stack[index] = Integer.parseInt(s);
            }
        }
       
        return stack[0];
      
    }
}

5、单调队列,双向队列:Deque  pollFirst(),pollLast(),peakFirst(),peskLast()

239. 滑动窗口最大值:  单调递减队列,维护单调队列的单调性

//利用双向队列解决问题
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        Deque<Integer> deque = new LinkedList<>();
        int[] res = new int[nums.length-k+1];
        int i = 0;
        while(i < nums.length){
            //维护单调队列:单调递减,带插入元素不满足该单调性,删除队尾元素
            //当前数值与队列中的元素从后往前进行对比,队列中元素小则删除
            while(!deque.isEmpty() && nums[i]>deque.peekLast()){
                deque.pollLast();
            }
            //添加新元素
            deque.offer(nums[i]);
            if(i >= k-1){
                //记录最大值
                res[i-k+1] = deque.peekFirst();
                //判断最大值是否为下次应去除元素
                if(deque.peekFirst() == nums[i-k+1]){
                    deque.pollFirst();
                }
            }
            i++;
        }
        return res;
    }
}

6、优先级队列:= 小顶堆、大顶堆 

大顶堆(堆头是最大元素,从大到小排列),小顶堆(堆头是最小元素,从小到大排)

对外接口只是从队头取元素,从队尾添加元素,内部元素是自动依照元素的权值排列

创建小顶堆:PriorityQueue<Map.Entry<Integer,Integer>> queue = new PriorityQueue<>((o1,o2)-> o1.getValue()-o2.getValue());  用到了Lambda表达式形参列表->返回值:相当于重写方法并调用

创建大顶堆:PriorityQueue<Map.Entry<Integer,Integer>> queue = new PriorityQueue<>((o1,o2)-> -(o1.getValue()-o2.getValue()));

//优先级队列:对外接口只是从队头取元素,从队尾添加元素,内部元素是自动依照元素的权值排列 = 小顶堆、大顶堆
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        //统计元素出现频率
        Map<Integer,Integer> map = new HashMap<>();
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        Set<Map.Entry<Integer,Integer>> entries = map.entrySet();
        //创建小顶堆,即排序
        PriorityQueue<Map.Entry<Integer,Integer>> queue = new PriorityQueue<>((o1,o2)-> o1.getValue()-o2.getValue());
        for(Map.Entry<Integer,Integer> e:entries){
            queue.offer(e);
            if(queue.size()>k){
                queue.poll();
            }
        }
        //记录数据
        int[] result = new int[k];
        for(int i = 0; i < k; i++){
            result[i] = (queue.poll()).getKey();
        }
        return result;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值