minds
提示:以下是本篇文章正文内容
可能单调栈的概念比较难形容,直接用题目来表达吧。
力扣:739. 每日温度;
思路:
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int length = temperatures.length;
int[] res = new int[length];
Stack<Integer> stack = new Stack<>();
stack.add(length - 1);
int index = length - 2;
while(index >= 0){
while(!stack.isEmpty() && temperatures[index] >= temperatures[stack.peek()]){
stack.pop();
}
if(stack.isEmpty()){
res[index] = 0;
}else{
res[index] = stack.peek() - index;
}
stack.push(index);
index--;
}
return res;
}
}
力扣:496. 下一个更大元素 I
class Solution {
// nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
// 先去找到nums2中,i位置处,对应右侧中,比i位置元素大的第一个元素
Stack<Integer> stack = new Stack<>();
// 因为 nums2 没有重复元素,利用一个hashMap存储
Map<Integer,Integer> map = new HashMap<>();
// initialization
int index = nums2.length;
int[] ans = new int[nums1.length];
map.put(nums2[index - 1], -1);
stack.add(index - 1);
index -= 2;
while(index >= 0){
while(!stack.isEmpty() && nums2[index] >= nums2[stack.peek()]){
stack.pop();
}
if(stack.isEmpty()){
map.put(nums2[index], -1);
}else{
map.put(nums2[index], nums2[stack.peek()]);
}
stack.push(index);
index--;
}
for(int i =0; i < nums1.length; i++){
ans[i] = map.get(nums1[i]);
}
return ans;
}
}
503.下一个更大元素II
class Solution {
// 返回循环数组中每个元素的下一个更大元素
public int[] nextGreaterElements(int[] nums) {
int length = nums.length;
int[] res = new int[length];
// initialization
Arrays.fill(res, -1);
// 单调栈
Stack<Integer> stack = new Stack<>();
// two times
for(int i = 0; i < 2 * length; i++){
while(!stack.isEmpty() && nums[i % length] > nums[stack.peek()]){
res[stack.peek()] = nums[i % length];
stack.pop();
}
stack.push(i % length);
}
return res;
}
}
42. 接雨水
思路:
class Solution {
// 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
/**
height: 数组,柱子高度
*/
public int trap(int[] height) {
// base case
int length = height.length;
if(length <= 2){
return 0;
}
// 定义一些变量
int sum = 0;// 最后接的雨水值
// 单调栈,栈顶到栈底是,按照元素值从小到大,但是存储的是数组中元素下标
Stack<Integer> stack = new Stack<>();
stack.push(0);
for(int i = 1; i < length; i++){
// 栈中是一定存在元素的
int stackTopIndex = stack.peek();// 栈顶中元素对应在height数组中的下标
// 如果新加入的元素,比栈顶的元素小,直接压入栈中
if(height[i] < height[stackTopIndex]){
stack.push(i);
}else if(height[i] == height[stackTopIndex]){
// 如果新加入的元素,和栈顶的元素值相同,弹出栈顶元素,并且将新元素加入栈中
stack.pop();
stack.push(i);
}else{
// 情况三:要压入栈中的元素值,大于栈顶的元素值
int top = stack.peek();
// 遍历每一个比即将压入栈中小的元素
while(!stack.isEmpty() && height[i] > height[top]){
int cur = stack.pop();// 当前元素为高度
// 算雨水量是根据宽度*高度
if(!stack.isEmpty()){
int left = stack.peek();
int h = Math.min(height[left], height[i]) - height[cur];
int w = i - left - 1;
int res = h * w;
sum += res;
top = stack.peek();
}
}
stack.push(i);
}
}
return sum;
}
}
单调栈:
class Solution {
public int trap(int[] height) {
int length =height.length;
// base case
if(length <= 2){
return 0;
}
// 采用单调栈
Stack<Integer> stack = new Stack<>();
stack.push(0);
int sum = 0;
// traverse
for(int i = 1; i < length; i++){
int top = stack.peek();
// condition one
if(height[i] < height[top]){
stack.push(i);
}else if(height[i] == height[top]){
// condition two
stack.pop();
stack.push(i);
}else{
// condition three
while(!stack.isEmpty() && height[i] > height[top]){
int cur = stack.pop();
if(!stack.isEmpty()){
int left = stack.peek();
int h = Math.min(height[i], height[left]) - height[cur];
int w = i - left - 1;
int res = h * w;
sum += res;
top = stack.peek();
}
}
stack.push(i);
}
}
return sum;
}
}
84.柱状图中最大的矩形
class Solution {
public int largestRectangleArea(int[] heights) {
int length = heights.length;
// 存储 i 位置,左边比它小的第一个元素的位置;
int[] left = new int[length];
left[0] = -1;
for(int i = 1; i < length; i++){
int index = i - 1;
while(index >= 0 && heights[i] <= heights[index]){
index--;
}
left[i] = index;
}
// 存储 i 位置,右边比它小的第一个元素的位置;
int[] right = new int[length];
right[length - 1] = length;
for(int i = length - 2; i >= 0; i--){
int index = i + 1;
while(index <length && heights[i] <= heights[index]){
index++;
}
right[i] = index;
}
// 遍历柱状图中每个柱子,更新最大矩形面积
int ans = 0;
for(int i = 0; i < length; i++){
int h = heights[i];
int w = right[i] - left[i] - 1;
int res = h * w;
// 判断
ans = ans > res ? ans : res;
}
return ans;
}
}
class Solution {
// 单调栈
/**
需要明白,柱状图中的面积取决于三个数:
左边比它小的柱状图,它自己,右边比它小的柱状图
所以在单调栈中存储的元素,从栈顶到栈底的元素是从大到小的
*/
public int largestRectangleArea(int[] heights) {
int length = heights.length;
int[] arr = new int[length + 2];
arr[0] = 0;
arr[length + 1] = 0;
for(int i = 0; i < length; i++){
arr[i + 1] = heights[i];
}
// 存储的是元素位置下标
Stack<Integer> stack = new Stack<>();
stack.push(0);
// 结果
int result = 0;
for(int i = 1; i < length + 2; i++){
int top = stack.peek();
if(arr[i] > arr[top]){
// 如果即将要压入栈中的元素,大于栈顶元素,就可直接压入栈中
stack.push(i);
}else if(arr[i] == arr[top]){
// 如果即将要压入栈中的元素,等于栈顶元素,先将栈顶元素弹出,再压入栈顶中
stack.pop();
stack.push(i);
}else{
// 如果即将要压入栈中的元素,小于栈顶元素,这就是需要计算最大矩形面积的地方
// 最大的矩形面积取决于三个数,当前柱状图的高度,左边界,有边界
while(!stack.isEmpty() && arr[i] < arr[top]){
top = stack.pop();
if(!stack.isEmpty()){
int w = i - stack.peek() - 1;
int h = arr[top];
int ans = w * h;
result = result > ans ? result : ans;
}
top = stack.peek();
}
stack.push(i);
}
}
return result;
}
}
重点: