1.单调栈
除了单调栈最经典的用法之外,在很多问题里单调栈还可以 维持求解答案的可能性
1)单调栈里的所有对象按照 规定好的单调性来组织
2)当某个对象进入单调栈时, 会从 栈顶开始 依次淘汰单调栈里 对后续求解答案没有帮助 的对象
3)每个对象从栈顶弹出的时 结算当前对象参与的答案,随后这个对象 不再参与后续求解答案的过程
4)其实是 先有对题目的分析!进而发现单调性,然后利用 单调栈的特征 去实现
单调栈结构(进阶)
时间限制:2秒 空间限制:256M
校招时部分企业笔试将禁止编程题跳出页面,为提前适应,练习时请使用在线自测,而非本地IDE。
描述
给定一个可能含有重复值的数组 arr,找到每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置。返回所有位置相应的信息。
输入描述:
第一行输入一个数字 n,表示数组 arr 的长度。 以下一行输入 n 个数字,表示数组的值
输出描述:
输出n行,每行两个数字 L 和 R,如果不存在,则值为 -1,下标从 0 开始。
示例1
输入:
7 3 4 1 5 6 2 7
复制
输出:
-1 2 0 2 -1 -1 2 5 3 5 2 -1 5 -1
复制
备注:
1≤𝑛≤10000001≤n≤1000000 −1000000≤𝑎𝑟𝑟𝑖≤1000000−1000000≤arri≤1000000
//改成Main public class Main { static int [] stack = new int[1000001]; static int right = 0; static int [][] ans = new int[1000001][2]; static int [] arr = new int[1000001]; static int n = 0; public static void main(String[] args) throws IOException{ BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); String [] str = bf.readLine().split(" "); n = Integer.parseInt(str[0]); String [] s = bf.readLine().split(" "); right = 0; int current = 0; for(int i = 0;i<n;i++){ arr [i] = Integer.parseInt(s[i]); //先查看栈里是否有东西,并且是否小于栈顶 while(right > 0&& arr[i] <= arr[stack[right-1]]){ //弹出栈顶 current = stack[--right]; //栈顶元素压着的作为比current小的最近的数 ans[current][0] = right > 0 ? stack[right-1]:-1; //弹出栈顶的作为右边比current小的数 ans[current][1] = i; } stack[right++] = i; } //遍历结束之后 //清算阶段 while(right>0){ int cur = stack[--right]; ans [cur][0] = right > 0 ? stack[right-1]:-1; ans [cur][1] = -1; } //修正阶段 for(int i = n-2;i>=0;i--){ if(ans[i][1]!=-1&&arr[ans[i][1]]==arr[i]){ ans[i][1] = ans[ans[i][1]][1]; } } PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); for (int i = 0; i < n; i++) { out.println(ans[i][0] + " " + ans[i][1]); } out.flush(); out.close(); } }
503. 下一个更大元素 II
已解答
中等
给定一个循环数组 nums
( nums[nums.length - 1]
的下一个元素是 nums[0]
),返回 nums
中每个元素的 下一个更大元素 。
数字 x
的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1
。
示例 1:
输入: nums = [1,2,1] 输出: [2,-1,2] 解释: 第一个 1 的下一个更大的数是 2; 数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
public static int[] nextGreaterElements(int[] nums) { Deque<Integer> stack = new LinkedList<>(); int [] ans = new int[nums.length]; for (int i = 0;i< nums.length;i++){ while (!stack.isEmpty()&&nums[stack.peek()]<nums[i]){ ans[stack.pop()] = nums[i]; } stack.push(i); } int size = stack.size(); for (int i = 0;i<nums.length;i++){ while (!stack.isEmpty()&&nums[i]>nums[stack.peek()]){ ans[stack.pop()] = nums[i]; } } while (!stack.isEmpty()){ ans[stack.pop()] = -1; } return ans; }
739. 每日温度
已解答
中等
提示
给定一个整数数组 temperatures
,表示每天的温度,返回一个数组 answer
,其中 answer[i]
是指对于第 i
天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0
来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73] 输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60] 输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90] 输出: [1,1,0]
提示:
-
1 <= temperatures.length <= 105
-
30 <= temperatures[i] <= 100
public static int [] answer; public static int [] stack = new int[10000]; public static int[] dailyTemperatures(int[] temperatures) { answer = new int [temperatures.length]; //指向数组栈的索引 int r = 0; //i指向temperatures的索引 //遍历整个温度数组 for (int i=0;i<temperatures.length;i++){ while (r>0&&temperatures[i]>temperatures[stack[r-1]]){ r--; //因为是i让r弹出,所以i出的温度是离r最近且大于i的 answer[stack[r]] = i-stack[r]; } //栈中存储的是索引 stack[r] = i; r++; } return answer; }
907. 子数组的最小值之和
已解答
中等
给定一个整数数组 arr
,找到 min(b)
的总和,其中 b
的范围为 arr
的每个(连续)子数组。
由于答案可能很大,因此 返回答案模 10^9 + 7
。
示例 1:
输入:arr = [3,1,2,4] 输出:17 解释: 子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。 最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。
示例 2:
输入:arr = [11,81,94,43,3] 输出:444
提示:
-
1 <= arr.length <= 3 * 104
-
1 <= arr[i] <= 3 * 104
static int [] stack = new int[30001]; static int r = 0; static int MOD = 1000000007; public static int sumSubarrayMins(int[] arr) { r= 0; int n = arr.length; long ans = 0; for(int i = 0;i<n;i++){ while(r>0&&arr[stack[r-1]]>=arr[i]){ int cur = stack[--r]; if (r==0){ ans = (ans + (i - cur) *(cur+1)*arr[cur] )%MOD; }else { ans = (ans + (long) (i - cur) *(cur-stack[r-1])*arr[cur])%MOD; } } stack[r++] = i; } while(r>0){ int cur = stack[--r]; if(r==0){ ans = (ans + (long) (n - cur) *(cur+1)*arr[cur])%MOD; }else{ ans = (ans + (long) (n - cur) *(cur-stack[r-1])*arr[cur])%MOD; } } return (int)ans; }
84. 柱状图中最大的矩形
已解答
困难
相关标签
相关企业
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
输入:heights = [2,1,5,6,2,3] 输出:10 解释:最大的矩形为图中红色区域,面积为 10
public static int [] stack = new int [100000]; public static int [][] ans = new int[100000][2]; public static int largestRectangleArea(int[] heights) { int r = 0; int result = 0; for (int i = 0;i<heights.length;i++){ while (r>0&&heights[stack[r-1]]>=heights[i]){ int cur = stack[--r]; ans[cur][0] = r>0 ? stack[r-1]:-1; ans[cur][1] = i; } stack[r++] = i; } while (r>0){ int cur = stack[--r]; ans[cur][0] = r>0 ? stack[r-1]:-1; ans[cur][1] = heights.length; } for (int i = heights.length-2;i>=0;i--){ if (ans[i][1]<heights.length&&heights[ans[i][1]] == heights[i]){ ans[i][1] = ans[ans[i][1]][1]; } } for (int i = 0;i<heights.length;i++){ result = Math.max(result,heights[i]*(ans[i][1]-ans[i][0]-1)); } return result; }
坚持完成练习,不懂的可以私信问我