public something solve(int[] a) { for (inti=0; i < a.length; i++) { while (!d.isEmpty() && a[i] ? a[d.peek()] 这里的偏序符号(?)取决于是递增(<)还是递减(>)栈) { // do something 求和 or 赋值 or 做出自己的处理 } d.push(i); } return something }
classSolution { privateintcalc(int[] a) { intn= a.length, res = 0; int[] b = newint[n + 2]; System.arraycopy(a, 0, b, 1, n); Deque<Integer> d = newArrayDeque<>(); // 代入模板,应该是第一个小于当前位置的值,因此是递增栈,这样两侧都是小于自身的,那么以自身为高度的矩形面积就可以通过当前位置和前一个位置求出 for (inti=0; i < n + 2; i++) { while (!d.isEmpty() && b[i] < b[d.peek()]) { intj= d.pop(); res = Math.max(res, (i - d.peek() - 1) * b[j]); } d.push(i); } return res; } publicintmaximalRectangle(char[][] a) { intn= a.length, m = a[0].length, res = 0; int[][] f = newint[n][m]; for (intj=0; j < m; j++) f[0][j] = a[0][j] - '0'; for (intj=0; j < m; j++) { for (inti=1; i < n; i++) { if (a[i][j] == '1') f[i][j] = f[i - 1][j] + (a[i][j] - '0'); } } for (int[] x : f) res = Math.max(res, calc(x)); return res; } }
单调队列
解决问题
滑动窗口的最大(最小)值
操作模板
1 2 3 4 5 6 7 8 9
publicvoidsolve(int[] a) { Deque<Integer> q = newArrayDeque<>(); for (inti=0; i < a.length; i++) { if (!q.isEmpty() && i - q.peekFirst() >= m) q.pollFirst(); while (!q.isEmpty() && a[i] > a[q.peekLast()]) q.pollLast(); // 这里的出队条件取决于递减还是递增,如果递减求最大,那么就是大于,否则小于 q.offer(i); if (i >= m - 1) System.out.println(a[q.peekFirst()]); } }
记忆方式
最小值 $\to$ 单调递增
最大值 $\to$ 单调递减
例题
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution { publicint[] maxSlidingWindow(int[] a, int m) { intn= a.length, p = 0; int[] res = newint[n - m + 1]; // 直接贴上来就行,刚好是符合我们要求的 Deque<Integer> q = newArrayDeque<>(); for (inti=0; i < a.length; i++) { if (!q.isEmpty() && i - q.peekFirst() >= m) q.pollFirst(); while (!q.isEmpty() && a[i] > a[q.peekLast()]) q.pollLast(); q.offer(i); if (i >= m - 1) res[p++] = a[q.peekFirst()]; } return res; } }