一、单调递减队列
package com.itheima.algorithms.leetcode;
import java.util.LinkedList;
public class MonotonicQueue {
private LinkedList<Integer> deque = new LinkedList<>();
public Integer peek() {
return deque.peekFirst();
}
public void poll() {
deque.pollFirst();
}
public void offer(Integer t) {
while(!deque.isEmpty() && deque.peekLast() < t) {
deque.pollLast();
}
deque.offerLast(t);
}
@Override
public String toString() {
return deque.toString();
}
public static void main(String[] args) {
MonotonicQueue q = new MonotonicQueue();
for (int i : new int[]{1, 3, -1, -3, 5, 3, 6, 7}) {
q.offer(i);
System.out.println(q);
}
}
}
运行结果:
[1]
[3]
[3, -1]
[3, -1, -3]
[5]
[5, 3]
[6]
[7]
1.1 最大滑动窗口
给你一个整数数组 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 <= 10^5-10^4 <= nums[i] <= 10^41 <= k <= nums.leng
class Solution {
static class MonotonicQueue {
private LinkedList<Integer> deque = new LinkedList<>();
public Integer peek() {
return deque.peekFirst();
}
public void poll() {
deque.pollFirst();
}
public void offer(Integer t) {
while (!deque.isEmpty() && deque.peekLast() < t) {
deque.pollLast();
}
deque.offerLast(t);
}
@Override
public String toString() {
return deque.toString();
}
}
public int[] maxSlidingWindow(int[] nums, int k) {
MonotonicQueue q = new MonotonicQueue();
int[] result = new int[nums.length - (k - 1)];
for (int i = 0; i < nums.length; i++) {
// 如果队列头部的元素超过了滑动窗口的范围,则移除
if (i >= k && nums[i - k] == q.peek()) {
q.poll();
}
int num = nums[i];
q.offer(num);
// 索引大于等于k时才开始计算滑动窗口内的最大值
if (i >= k - 1) {
// 单调递减队列队头的元素是最大的
result[i - (k - 1)] = q.peek();
}
}
return result;
}
}
二、单调递减栈
2.1 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5] 输出:9
提示:
n == height.length1 <= n <= 2 * 10^40 <= height[i] <= 10^5
class Solution {
static class Data {
int height;
int i; // 索引
public Data(int height, int i) {
this.height = height;
this.i = i;
}
@Override
public String toString() {
return String.valueOf(height);
}
}
/**
* 1. 维护一个单调递减栈
* 2. 当加入一个新元素时,如果发现需要弹出元素,表示遇到了一个凹陷的位置,此时应该计算雨水容量
*
* @param height
* @return
*/
public int trap(int[] height) {
LinkedList<Data> stack = new LinkedList<>();
int total = 0;
for (int i = 0; i < height.length; i++) {
Data right = new Data(height[i], i);
while (!stack.isEmpty() && stack.peek().height < right.height) {
Data pop = stack.pop();
Data left = stack.peek();
if (left != null) { // 计算水的容量
int width = right.i - left.i - 1;
int h = Math.min(left.height, right.height) - pop.height;
total += width * h;
}
}
stack.push(right);
}
return total;
}
}