首页 > 其他分享 >LeetCode 04 - 栈

LeetCode 04 - 栈

时间:2022-10-05 16:24:14浏览次数:62  
标签:04 nums int 元素 public queue new LeetCode

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

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

示例:
输入:"abbaca"
输出:"ca"

方法:使用栈

类似于判断括号序列是否有效,使用栈存储遍历过程中的字符,如果当前字符和栈顶相同,则出栈。

public String removeDuplicates(String s) {
    Deque<Character> stack = new LinkedList<>();
    for (char c : s.toCharArray()) {
        if (!stack.isEmpty() && stack.peek() == c)
            stack.pop();
        else
            stack.push(c);
    }
    StringBuilder builder = new StringBuilder();
    for (char c : stack) {
        builder.append(c);
    }
    return builder.reverse().toString();
}

155. 最小栈

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

分析:需要在常数时间内找到最小元素,所以需要借助额外的空间来存储最小元素信息。具体来说,在存储所有元素的栈之外,使用另一个栈来存储对应于每个元素位置的最小元素

在每次 push 操作中,除了将元素压入 stack ,还要比较该元素和 min_stack 栈顶元素的大小,将较小者压入 min_stack 栈。然后在每次 pop 操作中,需要将两个栈的栈顶元素同步弹出。这样每次找最小元素时,直接将 min_stack 栈顶元素弹出即可。

在 Java 中,使用 Deque 接口来实现栈结构,具体实现类为 LinkedList

class MinStack {

  private Deque<Integer> dataStack;
  private Deque<Integer> minDataStack;

  public MinStack() {
      this.dataStack = new LinkedList<>();
      this.minDataStack = new LinkedList<>();
      minDataStack.push(Integer.MAX_VALUE);
  }
  
  public void push(int val) {
      this.dataStack.push(val);
      int minData = this.minDataStack.peek();
      this.minDataStack.push(val < minData ? val : minData);
  }
  
  public void pop() {
      this.dataStack.pop();
      this.minDataStack.pop();
  }
  
  public int top() {
      return this.dataStack.peek();
  }
  
  public int getMin() {
      return this.minDataStack.peek();
  }
}

239. 滑动窗口最大值

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

方法一:优先队列

用优先队列实现一个大根堆,初始状态下,将数组的前 k 个元素放入堆中,然后向右移动窗口,不断将新元素放入队列。每加入一个新元素,检查当前堆顶元素(最大值)是否还在当前窗口,如果不在,则将其从堆中删除,如果还在,它就是当前窗口的最大值

为了方便知道堆顶元素是否在当前窗口,在堆中存储每个元素的同时,一并存储各自的索引,即队列中的元素类型为二元组 (num, index)

public int[] maxSlidingWindow(int[] nums, int k) {
    int n = nums.length;
    PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
        public int compare(int[] pair1, int[] pair2) {
            // 按照数值从大到小排列,数值相同的按照索引从大到小排列
            if (pair1[0] != pair2[0]) return pair2[0] - pair1[0];
            else return pair2[1] - pair1[1];
        }
    });
    // 将前 k 个元素入队
    for (int i = 0; i < k; i++) {
        queue.offer(new int[]{nums[i], i});
    }
    // 滑动窗口
    int[] result = new int[n-k+1];
    result[0] = queue.peek()[0];
    for (int i = k, j = 1; i < n; i++, j++) {
        queue.offer(new int[]{nums[i], i});
        while (queue.peek()[1] <= i - k) queue.poll();
        result[j] = queue.peek()[0]; // 堆顶元素加入结果
    }
    return result;
}

方法二:单调队列

遍历每个元素,对于当前元素 nums[i]

  • 首先将队尾中所有不大于 nums[i] 的元素所在位置删除(因为这些被删除的元素肯定不是当前窗口的最大值);
  • 然后将当前元素所在位置 i 入队,此时:
    • 队头元素如果在当前窗口,那它就是当前窗口的最大值;
    • 否则,将不在当前窗口的队头元素删除,最后剩下的队头元素就是当前窗口的最大值。

队列中保存的索引所对应的元素值,从队头到队尾是递减的,所以叫做单调队列。

因为在单调队列中添加元素时需要从队尾删除元素,而在确定当前窗口的最大值时需要从队头删除元素,所以需要使用双端队列

// 双端队列:
// --------------------
// 队尾 x x x x x x 队头
// --------------------
public int[] maxSlidingWindow(int[] nums, int k) {
    Deque<Integer> deque = new LinkedList<>();
    int n = nums.length;
    int[] result = new int[n-k+1];
    // 将前 k 个元素入队
    for (int i = 0; i < k; i++) {
        // 将队尾不大于当前元素的删除
        while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {
            deque.pollLast();
        }
        deque.offerLast(i);
    }
    result[0] = nums[deque.peekFirst()];
    // 遍历后续 n-k 个元素
    for (int i = k, j = 1; i < n; i++, j++) {
        while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {
            deque.pollLast();
        }
        deque.offerLast(i);
        // 将不在当前窗口的队头元素删除
        while (deque.peekFirst() <= i - k) deque.pollFirst();
        result[j] = nums[deque.peekFirst()];
    }
    return result;
}

347. 前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

任意顺序 返回 k 个频率最大的元素,就是在暗示使用 来做

那么使用大根堆还是小根堆呢?

维护一个大小为 k 的小根堆,那么堆顶元素就是当前堆中的最小元素,当堆中元素满了之后,在加入新元素时:

  • 如果新元素不大于堆顶元素,那么直接舍弃;
  • 否则将堆顶元素删除,将当前元素加入堆中。

这样一来,堆中保存的始终是目前为止最大的 k 个元素,遍历结束时,堆中的元素就是答案。

public int[] topKFrequent(int[] nums, int k) {
    // 统计出现次数
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int num : nums) {
        map.put(num, map.getOrDefault(num, 0) +1);
    }
    // 元素以 (num, frequency) 形式的二元组存储
    PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
        public int compare(int[] a, int[] b) {
            return a[1] - b[1]; // 排序靠前的优先级高(先出队)
        }
    });
    // 遍历 map 建堆
    int n = nums.length;
    for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
        int num = entry.getKey(), count = entry.getValue();
        if (queue.size() < k) {
            queue.offer(new int[]{num, count});
        } else if (queue.size() == k){
            if (queue.peek()[1] < count) {
                queue.poll();
                queue.offer(new int[]{num, count});
            }
        }
    }
    // 堆中的元素就是答案
    int[] result = new int[k];
    int i = 0;
    while (!queue.isEmpty()) {
        result[i++] = queue.poll()[0];
    }
    return result;
}

标签:04,nums,int,元素,public,queue,new,LeetCode
From: https://www.cnblogs.com/lzh1995/p/16755763.html

相关文章

  • LeetCode 03 - 链表
    707.设计链表设计链表的实现,您可以选择使用单链表或双链表。在链表类中实现这些功能:get(index):获取链表中第index个节点的值。如果索引无效,则返回1。addAtHead(val......
  • Codeforces Round #804 (Div. 2) C(组合 + mex)
    CodeforcesRound#804(Div.2)C(组合+mex)本萌新的第一篇题解qwq题目链接:传送门QAQ题意:给定一个\(\left[0,n-1\right]\)的排列,问有多少个排列,所有的子区间的......
  • [oeasy]教您玩转python - 0004 - 万行代码之梦
    继续运行......
  • [oeasy]教您玩转python - 0004 - 万行代码之梦
    ​ 继续运行......
  • LeetCode - 字符串类型题目
    剑指Offer05.替换空格请实现一个函数,把字符串 s 中的每个空格替换成"%20"。方法:双指针首先统计空格数量count,然后为原字符串数组扩展出2*count的空间,用来存......
  • leetcode 530. Minimum Absolute Difference in BST二叉搜索树的最小绝对差 (简单)
    一、题目大意给你一个二叉搜索树的根节点root,返回树中任意两不同节点值之间的最小差值。差值是一个正数,其数值等于两值之差的绝对值。示例1:输入:root=[4,2,6,1......
  • 1204. 错误票据
    https://www.acwing.com/problem/content/1206/模拟题,但是输入方式有点恶心可以用EOF方式读入,也可以用sstream读入sstream可以参考这份做法也有两种,可以定义bool数组遍......
  • 20221004(匈)
    20221004题目来源:George_Plover(乔治魄罗蛙)题目t1两个年轻人思路​ 考虑题目中所说的最优方案是什么。显然,如果只剩一堆,那么将这一堆直接选完就是最优方案。而如......
  • 20221004
    20221004(兄)题目来源:乔治魄罗蛙t1有两个年轻人题目背景有人问我,发生甚么事了?我一看,哦!原来是昨天,有两个年轻人,一个数学考\(150\),一个物理考\(110\),在教室里练题。......
  • [Oracle] LeetCode 41 First Missing Positive 思维
    Givenanunsortedintegerarraynums,returnthesmallestmissingpositiveinteger.Youmustimplementanalgorithmthatrunsin\(O(n)\)timeandusesconstan......