数据结构-栈与队列笔记

普通的双端队列

用栈实现队列

232. 用栈实现队列 - 力扣(LeetCode)

java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;

class MyQueue {

    // 使用双端队列(Deque)来实现一个队列
    Deque<Integer> input; // 用于存放新加入的元素
    Deque<Integer> output; // 用于存放准备出队的元素

    public MyQueue() {
        input = new ArrayDeque<>(); // 初始化input队列
        output = new ArrayDeque<>(); // 初始化output队列
    }
    
    public void push(int x) {
        // 将元素x添加到input队列的前端
        input.addFirst(x);
    }
    
    public int pop() {
        // 首先调用exchange方法,确保output队列中有元素
        exchange();
        // 从output队列的前端移除并返回元素
        return output.removeFirst();
    }
    
    public int peek() {
        // 首先调用exchange方法,确保output队列中有元素
        exchange();
        // 返回output队列前端的元素,但不移除它
        return output.getFirst();
    }
    
    public boolean empty() {
        // 如果input和output队列都为空,则返回true,表示队列为空
        return input.isEmpty() && output.isEmpty();
    }

    public void exchange() {
        // 如果output队列不为空,则不需要交换,直接返回
        if (!output.isEmpty()) {
            return;
        }
        // 当output队列为空时,将input队列中的所有元素转移到output队列
        while (!input.isEmpty()) {
            int temp = input.removeFirst(); // 从input队列前端移除元素
            output.addFirst(temp); // 将移除的元素添加到output队列的前端
        }
    }
}

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue(); // 创建MyQueue对象
 * obj.push(x); // 将元素x添加到队列
 * int param_2 = obj.pop(); // 移除并返回队列前端的元素
 * int param_3 = obj.peek(); // 返回队列前端的元素,但不移除
 * boolean param_4 = obj.empty(); // 检查队列是否为空
 */

有效的括号(难)

20. 有效的括号 - 力扣(LeetCode)

java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;

class Solution {
    public boolean isValid(String s) {
        // 使用双端队列(Deque)来存储尚未匹配的右括号
        Deque<Character> deque = new ArrayDeque<>();

        // 遍历字符串s中的每个字符
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i); // 获取当前遍历到的字符

            // 如果当前字符是左括号,将其对应的右括号添加到队列的前端
            if (ch == '(') {
                deque.addFirst(')');
            } else if (ch == '{') {
                deque.addFirst('}');
            } else if (ch == '[') {
                deque.addFirst(']');
            } else {
                // 如果当前字符是右括号
                // 检查栈是否为空或者栈顶元素是否与当前右括号匹配
                if (deque.isEmpty() || ch != deque.getFirst()) {
                    // 如果栈为空或者栈顶元素不匹配,说明括号序列无效,返回false
                    return false;
                } else {
                    // 如果栈顶元素与当前右括号匹配,从队列中移除栈顶元素
                    deque.removeFirst();
                }
            }
        }

        // 最后检查栈是否为空,如果为空,说明所有括号都正确匹配,返回true;否则返回false
        return deque.isEmpty();
    }
}

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

1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)

java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringBuilder;

class Solution {
    public String removeDuplicates(String s) {
        // 使用双端队列(Deque)来存储不重复的字符
        Deque<Character> deque = new ArrayDeque<>();

        // 遍历字符串s中的每个字符
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i); // 获取当前遍历到的字符

            // 如果队列不为空且队列的第一个字符与当前字符相同
            if (!deque.isEmpty() && deque.getFirst() == ch) {
                // 移除队列中的第一个字符
                deque.removeFirst();
            } else {
                // 否则,将当前字符添加到队列的前端
                deque.addFirst(ch);
            }
        }

        // 使用StringBuilder来构建最终的字符串
        StringBuilder sb = new StringBuilder();
        // 遍历队列,将队列中的字符添加到StringBuilder中
        while (!deque.isEmpty()) {
            sb.append(deque.removeLast()); // 从队列的后端移除字符并添加到StringBuilder
        }

        // 将StringBuilder转换为字符串并返回
        return sb.toString();
    }
}

逆波兰表达式求值

150. 逆波兰表达式求值 - 力扣(LeetCode)

java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;

class Solution {
    public int evalRPN(String[] tokens) {
        // 使用双端队列(Deque)来存储操作数
        Deque<Integer> deque = new ArrayDeque<>();

        // 遍历tokens数组中的每个元素
        for (int i = 0; i < tokens.length; i++) {
            String ch = tokens[i]; // 获取当前遍历到的元素

            // 如果当前元素是运算符
            if (ch.equals("+")) {
                // 从队列中弹出前两个操作数
                int first = deque.removeFirst();
                int second = deque.removeFirst();
                // 计算它们的和,并将其压入队列前端
                int sum = first + second;
                deque.addFirst(sum);
            } else if (ch.equals("-")) {
                // 从队列中弹出前两个操作数
                int first = deque.removeFirst();
                int second = deque.removeFirst();
                // 计算它们的差,并将其压入队列前端
                int sum = second - first;
                deque.addFirst(sum);
            } else if (ch.equals("*")) {
                // 从队列中弹出前两个操作数
                int first = deque.removeFirst();
                int second = deque.removeFirst();
                // 计算它们的乘积,并将其压入队列前端
                int sum = first * second;
                deque.addFirst(sum);
            } else if (ch.equals("/")) {
                // 从队列中弹出前两个操作数
                int first = deque.removeFirst();
                int second = deque.removeFirst();
                // 计算它们的商,并将其压入队列前端
                // 注意:这里假设不会出现除以零的情况
                int sum = second / first;
                deque.addFirst(sum);
            } else {
                // 如果当前元素不是运算符,将其转换为整数并压入队列前端
                deque.addFirst(Integer.parseInt(ch));
            }
        }

        // 返回队列中的第一个元素,即表达式的结果
        return deque.getFirst();
    }
}

单调队列

滑动窗口最大值(难)

239. 滑动窗口最大值 - 力扣(LeetCode)

java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;

class MyDeque {
    Deque<Integer> deque; // 双端队列,用于存储元素

    MyDeque() {
        deque = new ArrayDeque<>(); // 初始化双端队列
    }

    // 尝试移除队列头部的元素,如果头部元素等于val
    boolean remove(int val) {
        if (!deque.isEmpty() && deque.getFirst() == val) {
            deque.removeFirst(); // 移除队列头部元素
        }
        return true; // 无论是否移除,都返回true
    }

    // 将val添加到队列中,移除所有比val小的尾部元素
    boolean add(int val) {
        while (!deque.isEmpty() && deque.getLast() < val) {
            deque.removeLast(); // 移除队列尾部元素
        }
        deque.addLast(val); // 添加val到队列尾部
        return true; // 返回true表示添加成功
    }

    // 返回队列头部的元素,即当前窗口中的最大值
    int maxValue() {
        return deque.getFirst(); // 返回队列头部元素
    }
}

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length; // 输入数组的长度
        int[] ret = new int[n - k + 1]; // 存储每个窗口的最大值
        MyDeque deque = new MyDeque(); // 创建MyDeque对象

        // 将数组的前k个元素添加到队列中
        for (int i = 0; i < k; i++) {
            deque.add(nums[i]);
        }

        // 将第一个窗口的最大值添加到结果数组中
        int index = 0;
        ret[index++] = deque.maxValue();

        // 遍历数组,从索引k到n-1
        for (int i = k; i < n; i++) {
            // 移除窗口外的元素
            deque.remove(nums[i - k]);
            // 将当前元素添加到队列中
            deque.add(nums[i]);
            // 将当前窗口的最大值添加到结果数组中
            ret[index++] = deque.maxValue();
        }

        return ret; // 返回结果数组
    }
}

优先队列

前 K 个高频元素(难)

. - 力扣(LeetCode)

java 复制代码
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        // 创建一个HashMap来存储数组中每个数字的出现次数
        HashMap<Integer, Integer> hashmap = new HashMap<>();
        for (int num : nums) {
            // 对于数组中的每个数字,如果它已经在HashMap中,则增加其计数,否则添加到HashMap中并设置计数为1
            hashmap.put(num, hashmap.getOrDefault(num, 0) + 1);
        }

        // 创建一个小顶堆(PriorityQueue),用于存储二元组(数字,出现次数)
        // 比较器使用Lambda表达式,根据二元组的第二个元素(出现次数)来比较
        PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2) -> pair1[1] - pair2[1]);
        for (Map.Entry<Integer, Integer> entry : hashmap.entrySet()) {
            // 遍历HashMap中的每个条目
            if (pq.size() < k) {
                // 如果堆的大小小于k,则直接添加当前条目
                pq.add(new int[]{entry.getKey(), entry.getValue()});
            } else {
                // 如果堆的大小已经达到k,并且堆顶元素的出现次数小于当前条目的出现次数
                if (pq.peek()[1] < entry.getValue()) {
                    // 移除堆顶元素(出现次数最小的元素)
                    pq.poll();
                    // 添加当前条目
                    pq.add(new int[]{entry.getKey(), entry.getValue()});
                }
            }
        }

        // 创建一个数组来存储最终的k个最频繁出现的数字
        int[] ret = new int[k];
        for (int i = 0; i < k; i++) {
            // 依次从堆中取出元素,填充到数组中
            ret[i] = pq.poll()[0];
        }
        // 返回结果数组
        return ret;    
    }
}
相关推荐
静能生慧14 分钟前
倪师学习笔记-天纪-斗数简介
笔记·学习·倪师·玄学
跟着杰哥学嵌入式21 分钟前
数据结构_day1
数据结构
李小白6630 分钟前
数据结构前置知识(下)
数据结构
楠了个难32 分钟前
RGB转HDMI方案、MS7210驱动——FPGA学习笔记20
笔记·学习·fpga开发
夜喵YM1 小时前
[YM]模板-归并排序
java·数据结构·c++·算法·排序算法
修炼室1 小时前
掌握寻找峰值元素的高效算法:从线性遍历到二分查找
数据结构·算法
冉佳驹1 小时前
数据结构 ——— 单链表oj题:相交链表(链表的共节点)
c语言·数据结构·算法·链表
IronmanJay1 小时前
【LeetCode每日一题】——679.24 点游戏
数据结构·算法·leetcode·回溯·递归·679.24 点游戏·24点游戏
姚杰献2 小时前
股市入门常见术语介绍
笔记·金融·web3·区块链·程序员创富
rachel_wanna_die2 小时前
【深圳大学】大学物理实验2 双光栅测微振动预习题参考
笔记