深入浅出Java算法:栈与队列处理类问题

深入浅出Java算法:栈与队列处理类问题

栈和队列是两种重要的线性数据结构,在算法问题中应用广泛。下面我将用通俗易懂的方式介绍常见的栈和队列处理问题及其解决方案。

一、栈篇

1. 有效的括号

问题:判断字符串中的括号是否有效匹配

java 复制代码
public boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    for (char c : s.toCharArray()) {
        if (c == '(' || c == '[' || c == '{') {
            stack.push(c);
        } else {
            if (stack.isEmpty()) return false;
            char top = stack.pop();
            if ((c == ')' && top != '(') || 
                (c == ']' && top != '[') || 
                (c == '}' && top != '{')) {
                return false;
            }
        }
    }
    return stack.isEmpty();
}

2. 最小栈

问题:设计一个支持push、pop、top操作,并能检索最小元素的栈

java 复制代码
class MinStack {
    private Stack<Integer> stack;
    private Stack<Integer> minStack;

    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }
    
    public void push(int val) {
        stack.push(val);
        if (minStack.isEmpty() || val <= minStack.peek()) {
            minStack.push(val);
        }
    }
    
    public void pop() {
        if (stack.pop().equals(minStack.peek())) {
            minStack.pop();
        }
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

3. 逆波兰表达式求值

问题:根据逆波兰表示法(后缀表达式)求表达式的值

java 复制代码
public int evalRPN(String[] tokens) {
    Stack<Integer> stack = new Stack<>();
    for (String token : tokens) {
        if ("+-*/".contains(token)) {
            int b = stack.pop();
            int a = stack.pop();
            switch (token) {
                case "+": stack.push(a + b); break;
                case "-": stack.push(a - b); break;
                case "*": stack.push(a * b); break;
                case "/": stack.push(a / b); break;
            }
        } else {
            stack.push(Integer.parseInt(token));
        }
    }
    return stack.pop();
}

4. 每日温度

问题:给定每日温度列表,返回需要等待多少天才能有更高温度的天数

java 复制代码
public int[] dailyTemperatures(int[] temperatures) {
    Stack<Integer> stack = new Stack<>();
    int[] result = new int[temperatures.length];
    for (int i = 0; i < temperatures.length; i++) {
        while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
            int prevIndex = stack.pop();
            result[prevIndex] = i - prevIndex;
        }
        stack.push(i);
    }
    return result;
}

二、队列篇

1. 用栈实现队列

问题:使用栈实现队列的push、pop、peek和empty操作

java 复制代码
class MyQueue {
    private Stack<Integer> inStack;
    private Stack<Integer> outStack;

    public MyQueue() {
        inStack = new Stack<>();
        outStack = new Stack<>();
    }
    
    public void push(int x) {
        inStack.push(x);
    }
    
    public int pop() {
        if (outStack.isEmpty()) {
            while (!inStack.isEmpty()) {
                outStack.push(inStack.pop());
            }
        }
        return outStack.pop();
    }
    
    public int peek() {
        if (outStack.isEmpty()) {
            while (!inStack.isEmpty()) {
                outStack.push(inStack.pop());
            }
        }
        return outStack.peek();
    }
    
    public boolean empty() {
        return inStack.isEmpty() && outStack.isEmpty();
    }
}

2. 滑动窗口最大值

问题:给定数组和滑动窗口大小,返回每次窗口滑动时的最大值

java 复制代码
public int[] maxSlidingWindow(int[] nums, int k) {
    if (nums == null || nums.length == 0) return new int[0];
    
    int[] result = new int[nums.length - k + 1];
    Deque<Integer> deque = new ArrayDeque<>();
    
    for (int i = 0; i < nums.length; i++) {
        // 移除不在窗口范围内的元素
        while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
            deque.pollFirst();
        }
        
        // 移除比当前元素小的元素,保持队列递减
        while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
            deque.pollLast();
        }
        
        deque.offerLast(i);
        
        // 当窗口形成时记录最大值
        if (i >= k - 1) {
            result[i - k + 1] = nums[deque.peekFirst()];
        }
    }
    
    return result;
}

3. 设计循环队列

问题:设计一个循环队列实现

java 复制代码
class MyCircularQueue {
    private int[] queue;
    private int head;
    private int tail;
    private int size;
    private int capacity;

    public MyCircularQueue(int k) {
        queue = new int[k];
        head = 0;
        tail = -1;
        size = 0;
        capacity = k;
    }
    
    public boolean enQueue(int value) {
        if (isFull()) return false;
        tail = (tail + 1) % capacity;
        queue[tail] = value;
        size++;
        return true;
    }
    
    public boolean deQueue() {
        if (isEmpty()) return false;
        head = (head + 1) % capacity;
        size--;
        return true;
    }
    
    public int Front() {
        return isEmpty() ? -1 : queue[head];
    }
    
    public int Rear() {
        return isEmpty() ? -1 : queue[tail];
    }
    
    public boolean isEmpty() {
        return size == 0;
    }
    
    public boolean isFull() {
        return size == capacity;
    }
}

三、栈与队列综合问题

1. 柱状图中最大的矩形

问题:在柱状图中找出能勾勒出的最大矩形的面积

java 复制代码
public int largestRectangleArea(int[] heights) {
    Stack<Integer> stack = new Stack<>();
    int maxArea = 0;
    int i = 0;
    
    while (i <= heights.length) {
        int h = (i == heights.length) ? 0 : heights[i];
        if (stack.isEmpty() || h >= heights[stack.peek()]) {
            stack.push(i++);
        } else {
            int top = stack.pop();
            int width = stack.isEmpty() ? i : i - stack.peek() - 1;
            maxArea = Math.max(maxArea, heights[top] * width);
        }
    }
    
    return maxArea;
}

2. 用队列实现栈

问题:使用队列实现栈的push、pop、top和empty操作

java 复制代码
class MyStack {
    private Queue<Integer> queue;

    public MyStack() {
        queue = new LinkedList<>();
    }
    
    public void push(int x) {
        queue.offer(x);
        int size = queue.size();
        // 将新元素前面的所有元素重新入队
        for (int i = 0; i < size - 1; i++) {
            queue.offer(queue.poll());
        }
    }
    
    public int pop() {
        return queue.poll();
    }
    
    public int top() {
        return queue.peek();
    }
    
    public boolean empty() {
        return queue.isEmpty();
    }
}

总结

栈和队列问题的解决技巧:

  1. 栈的典型应用

    • 括号匹配问题
    • 表达式求值
    • 单调栈解决边界问题
    • 深度优先搜索(DFS)
  2. 队列的典型应用

    • 广度优先搜索(BFS)
    • 滑动窗口问题
    • 任务调度
  3. 常用技巧

    • 使用辅助栈/队列(如最小栈问题)
    • 双栈实现队列/双队列实现栈
    • 单调栈/单调队列解决极值问题
    • 循环队列的实现技巧

记住解决这类问题的关键:

  • 理解栈(LIFO)和队列(FIFO)的基本特性
  • 画图辅助理解操作过程
  • 考虑边界条件(空栈/队列、单个元素等)
  • 合理选择数据结构和算法

掌握这些基础问题的解法,能够帮助你更好地解决更复杂的算法问题!

相关推荐
撰卢1 分钟前
MySQL 1366 - Incorrect string value:错误
android·数据库·mysql
恋猫de小郭35 分钟前
Flutter 合并 ‘dot-shorthands‘ 语法糖,Dart 开始支持交叉编译
android·flutter·ios
牛马程序小猿猴38 分钟前
15.thinkphp的上传功能
android
林家凌宇1 小时前
Flutter 3.29.3 花屏问题记录
android·flutter·skia
时丶光2 小时前
Android 查看 Logcat (可纯手机方式 无需电脑)
android·logcat
血手人屠喵帕斯2 小时前
事务连接池
android·adb
恋猫de小郭3 小时前
React Native 前瞻式重大更新 Skia & WebGPU & ThreeJS,未来可期
android·javascript·flutter·react native·react.js·ios
一人一萧十只猫�3 小时前
MySQL 从入门到精通(三):日志管理详解 —— 从排错到恢复的核心利器
android·mysql·adb
黎猫大侠6 小时前
一次Android Fragment内存泄露的bug解决记录|Fragment not attach to an Activity
android·bug
袁震9 小时前
android HashMap和List该如何选择
android·hashmap·sparsearray