问题模型:给定一个序列,求这个序列当中,每一个数左边比它小而且离它最近的数(或者右边,比它大而且离它最近的数)
比如:给定一个数组,求每个元素左侧比它小,而且离它最近的元素是多少
维护一个单调递增的栈(越往上越大)
实现如下:
for(int i=0;i<nums.length;i++)
{
while(stack.size()!=0&&stack.top()>=nums[i])
{
stack.pop();
}
//跳出循环说明此时栈内为空,或者栈顶元素小于nums[i]
//这时就可以把nums[i]加入到栈顶,栈仍然维持单调递增
stack.push(nums[i]);
}
以上只是维护了一个单调递增的栈,由于还要统计出每个元素的左侧第一个比它小的数,所以还要再这个代码的基础上加几行代码:
for(int i=0;i<nums.length;i++)
{
while(stack.size()!=0&&stack.top()>=nums[i])
{
stack.pop();
}
//跳出循环说明此时栈内为空,或者栈顶元素小于nums[i]
//如果栈为空,那就为-1
if(stack.size()==0)
{
nums[i]=-1;
}
else//如果栈不为空,那就等于栈顶元素
{
nums[i]=stack.top();
}
//这时就可以把nums[i]加入到栈顶,栈仍然维持单调递增
stack.push(nums[i]);
}
单调栈还是栈,只是通过一些设置,使得每次新元素进栈后,栈内的元素都保持有序(单调递增或者单调递减)
比如构建一个单调递增栈:
从栈顶到栈底,元素大小依次递增(也就是说越往下,元素越大)
比如:
一维数组中,寻找任意一个元素右边第一个比自己大的数,或者是一个元素左边第一个比自己小的数的时候就要用到单调栈
例题1:力扣739 每日温度
题目意思:找出每一天要过几天才能碰到一个更高的温度
nums = [73, 74, 75, 71, 71, 72, 76, 73]
总结就是:构造一个单调递增栈,从栈顶到栈底元素越来越大,
将nums数组中每一个元素nums[i]进栈之前,都要和此时栈顶的元素nums[stack.top()]进行比较
如果nums[i]小于等于栈顶元素,就进栈
如果nums[i]大于栈顶元素,就把栈顶元素出栈,继续和新的栈顶元素比较,直到比新的栈顶元素小或者栈空了才进栈
也就是:(1)小于等于栈顶元素或者栈为空才进栈
(2)有元素出栈,才更新result数组的值,result[要出栈的元素下标]=]要进栈的元素下标-要出栈的元素下标
class Solution
{
public int[] dailyTemperatures(int[] nums)
{
int[] result=new int[nums.length];
Stack<Integer> stack=new Stack();
stack.push(0);
for(int i=1;i<nums.length;i++)
{
if(nums[i]<=nums[stack.peek()]||stack.size()==0)
{
stack.push(i);
}
if(nums[i]>nums[stack.peek()])
{
while(stack.size()!=0&&nums[i]>nums[stack.peek()])
{
int temp=stack.peek();
result[temp]=i-temp;
stack.pop();
}
//跳出这个循环之后,要么栈空了,要么栈顶元素比nums[i]大了
stack.push(i);
}
}
return result;
}
}
站在栈顶元素的角度,只有碰到比自己大的元素,它才被弹出栈
如果要找出下一个更大的元素:
class Solution
{
public int[] nextGreaterElements(int[] nums)
{
int[] result=new int[nums.length];
Arrays.fill(result,-1);
Stack<Integer> stack=new Stack();
stack.push(0);
for(int i=1;i<nums.length;i++)
{
if(nums[i]<=nums[stack.peek()]||stack.size()==0)
{
stack.push(i);
}
if(nums[i]>nums[stack.peek()])
{
while(stack.size()!=0&&nums[i]>nums[stack.peek()])
{
int temp=stack.peek();
result[temp]=nums[i];
stack.pop();
}
//跳出这个循环之后,要么栈空了,要么栈顶元素比nums[i]大了
stack.push(i);
}
}
return result;
}
}
输入一个数组 nums
,请你返回一个等长的数组,这个数组中的元素是nums数组中每个元素下一个更大的元素(如果后面没有比这个数更大的数,那就存-1)
把数组的元素想象成并列站立的人,元素大小想象成人的身高
那么显然nums数组中第一个元素2的下一个更大元素就是4(第一个比2高的元素)
int[] nextGreaterElement(int[] nums)
{
int n = nums.length;
// 存放答案的数组
int[] res = new int[n];
Stack<Integer> stack = new Stack<>();
//从最后一个元素开始往栈里放,一直到将最后一个元素放进栈里
for (int i = n - 1; i >= 0; i--)
{
//
while (stack.isEmpty()==false && stack.peek() <= nums[i])
{
// 矮个起开,反正也被挡着了。。。
s.pop();
}
// nums[i] 身后的更大元素
res[i] = s.isEmpty() ? -1 : s.peek();
s.push(nums[i]);
}
return res;
}