leetcode-栈、队列、优先队列、双端队列

数据结构简介

  1. 栈(Stack):

    • 概念:栈是一种后进先出(Last-In-First-Out,LIFO)的数据结构,类似于现实生活中的堆叠物品。
    • 实现:在Java中,可以使用数组或链表来实现栈。数组实现的栈称为顺序栈,链表实现的栈称为链式栈。
    • 常见操作:
      • 入栈(push):将元素添加到栈顶。
      • 出栈(pop):从栈顶移除一个元素,并返回该元素。
      • 获取栈顶元素(peek):获取栈顶元素,但不进行删除操作。
    • 应用场景:方法调用栈、表达式求值、括号匹配等。
  2. 队列(Queue):

    • 概念:队列是一种先进先出(First-In-First-Out,FIFO)的数据结构,类似于现实生活中排队的情况。
    • 实现:在Java中,可以使用数组或链表来实现队列。数组实现的队列称为顺序队列,链表实现的队列称为链式队列。
    • 常见操作:
      • 入队(enqueue):将元素添加到队尾。
      • 出队(dequeue):从队头移除一个元素,并返回该元素。
      • 获取队头元素(peek):获取队头元素,但不进行删除操作。
    • 应用场景:任务调度、消息传递、广度优先搜索等。
  3. 优先队列(Priority Queue):

    • 概念:优先队列是一种特殊的队列,其中每个元素都有一个优先级,优先级高的元素先出队。
    • 实现:在Java中,可以使用二叉堆、斐波那契堆等数据结构来实现优先队列。
    • 常见操作:
      • 插入元素(insert):将元素按照优先级插入队列。
      • 删除最高优先级元素(remove):删除并返回具有最高优先级的元素。
      • 获取最高优先级元素(peek):获取具有最高优先级的元素,但不进行删除操作。
    • 应用场景:任务调度、最小/最大K个元素查找、Dijkstra算法等。
  4. 双端队列(Deque):

    • 概念:双端队列是一种允许在两端进行插入和删除操作的队列。
    • 实现:在Java中,可以使用数组或链表来实现双端队列。数组实现的双端队列称为顺序双端队列,链表实现的双端队列称为链式双端队列。
    • 常见操作:
      • 头部插入(addFirst):将元素插入到队头。
      • 尾部插入(addLast):将元素插入到队尾。
      • 头部删除(removeFirst):删除并返回队头元素。
      • 尾部删除(removeLast):删除并返回队尾元素。
      • 获取队头元素(peekFirst):获取队头元素,但不进行删除操作。
      • 获取队尾元素(peekLast):获取队尾元素,但不进行删除操作。

min-stack

题目描述

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

示例

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

提示

  • -231 <= val <= 231 - 1
  • poptop 和 getMin 操作总是在 非空栈 上调用
  • pushpoptop, and getMin最多被调用 3 * 104 次

题解

思路

        用两个栈实现,一个存储原数据,一个存储最小值数据。

代码

class MinStack {
    Deque<Integer> xStack;
    Deque<Integer> minStack;

    public MinStack() {
        xStack = new LinkedList<Integer>();
        minStack = new LinkedList<Integer>();
        minStack.push(Integer.MAX_VALUE);

    }
    
    public void push(int val) {
        xStack.push(val);
        minStack.push(Math.min(minStack.peek(), val));
    }
    
    public void pop() {
        xStack.pop();
        minStack.pop();
    }
    
    public int top() {
        return xStack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

largest-rectangle-in-histogram

题目描述

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例

示例 1:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

输入: heights = [2,4]
输出: 4

提示

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

题解

思路

找到每个柱子的最左面小于它的柱子,记录下标,找到右边小于它的柱子记录下标。

栈内元素和当前柱子高度比较,大于当前柱子弹出。小于当前柱子记录其下标

代码

class Solution {
    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
        int[] left = new int[n];
        int[] right = new int[n];
        
        Deque<Integer> mono_stack = new ArrayDeque<Integer>();
        for (int i = 0; i < n; ++i) {
            while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
                mono_stack.pop();
            }
            left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());
            mono_stack.push(i);
        }

        mono_stack.clear();
        for (int i = n - 1; i >= 0; --i) {
            while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
                mono_stack.pop();
            }
            right[i] = (mono_stack.isEmpty() ? n : mono_stack.peek());
            mono_stack.push(i);
        }
        
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
        }
        return ans;
    }
}

sliding-window-maximum

题目描述

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 

示例

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

题解

思路

定义数组长度为n-k+1 保存结果。

定义双端队列保存窗口内数组下标

遍历数组,判断队列首元素值(下标)是否超出窗口大小 i - k +1;

判断队列尾元素值(下标)对应的数组元素值,和当前遍历的数组元素值比较大小,比队列元素大,弹出队列尾元素。

将数组下标添加到队列尾部。

代码

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        // Verify abnormal boundaries
        if (nums == null || nums.length == 0 || k <= 0) {
            return new int[0];
        }

        int n = nums.length;
        int[] result = new int[n - k + 1];
        int ri = 0;

        // Use a deque to store indices of elements in the window in descending order
        Deque<Integer> deque = new ArrayDeque<>();

        for (int i = 0; i < nums.length; i++) {
            // Remove indices that are out of the current window
            while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
                deque.pollFirst();
            }

            // Remove indices of elements smaller than the current element from the deque
            while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
                deque.pollLast();
            }

            // Add the current index to the deque
            deque.offerLast(i);

            // The first element in the deque is always the maximum in the window
            if (i >= k - 1) {
                result[ri++] = nums[deque.peekFirst()];
            }
        }

        return result;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值