LeeCode 栈与队列问题(二)

LeeCode 239: 滑动窗口最大值

题目描述

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

建立模型

  1. 单调队列:保存还未被删除的下标, 下标对应的值单调递减
  2. 对于前 k 个数,下标\(0 \le i < j < k\),若 \(nums[i] \ge nums[j]\),则 nums[i]永远不会成为最大值,无需保存
  3. 对于 [k, nums.length() - 1],循环比较队尾元素和当前元素的大小关系,若当前元素大于等于队尾元素则说明队尾元素永远不会成为最大值,无需保存;
  4. 然后插入当前元素下标

代码实现

# Python3 实现
def MaxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
    # 特殊情况
    if k >= len(nums):
        return max(nums)
    
    # 使用双端队列保存下标
    queue = collections.deque()
    
    # 前 k 个元素
    for i in range(k):
        while queue and nums[queue[-1]] <= nums[i]:
            queue.pop()
        queue.append(i)
    
    res = [nums[queue[0]]]
    for i in range(k, len(nums)):
        while queue and nums[queue[-1]] <= nums[i]:
            queue.pop()
        queue.append(i)
        
        while queue[0] <= i - k:
            queue.popleft()
        res.append(nums[queue[0]])
    return res
// Java 实现
public int[] maxSlidingWindow(int[] nums, int k) {
  if (k >= nums.length) {
    // return max(nums);
  }

  Deque<Integer> deque = new ArrayDeque<>();

  for (int i = 0; i < k; i++) {
    while(!deque.isEmpty() && nums[deque.getLast()] <= nums[i]) {
      deque.removeLast();
    }
    deque.add(i);
  }

  int[] res = new int[nums.length - k + 1];
  res[0] = nums[deque.getFirst()];
  int index = 1;

  for (int i = k; i < nums.length; i++) {
    while(!deque.isEmpty() && nums[deque.getLast()] <= nums[i]) {
      deque.removeLast();
    }
    deque.add(i);
    while (deque.getFirst() <= i - k) {
      deque.removeFirst();
    }

    res[index++] = nums[deque.getFirst()];
  }

  return res;
}

LeeCode 347: 前 K 个高频元素

题目描述

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

建立模型

这是一个堆的问题,这类问题还有比如前K个高频单词最小K个数等。

  1. 遍历数组统计所有出现的数字和频数
  2. 建立一个存储K个元素的小顶堆(自定义排序规则),每次比较堆顶元素和当前元素
  3. 若当前元素频数大于堆顶元素,则将堆顶元素弹出,添加当前元素
  4. 返回堆中的所有元素

代码实现

// Java 实现
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);
  }

  /**
         * 自定义排序规则
         * 按照数组第2个元素值从小到大排序
         */
  Comparator<int[]> comparator = new Comparator<int[]>() {

    @Override
    public int compare(int[] o1, int[] o2) {
      // TODO Auto-generated method stub
      return o1[1] - o2[1];
    }

  }; 
  // 小顶堆的实现
  PriorityQueue<int[]> queue = new PriorityQueue<>(comparator);

  for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
    int num = entry.getKey();
    int value = entry.getValue();

    if (queue.size() < k) {
      queue.offer(new int[]{num, value});
    }
    else {
      if (queue.peek()[1] < value) {
        queue.poll();
        queue.offer(new int[]{num, value});
      }
    }
  }

  int[] res = new int[k];
  int index = 0;
  while (index < k) {
    res[index++] = queue.poll()[0];
  }

  return res;
}
posted @ 2022-07-09 23:26  ylyzty  阅读(14)  评论(0编辑  收藏  举报