单调栈:
保持调顺序的栈。
单调递增栈:从底到定从小到大排序,解决寻找最近的比本身值小的左或右的元素;
具体来说:
单调递增栈可以找到左起第一个比当前数字小的元素。比如数组 [2 1 4 6 5],刚开始空栈故2入栈,数字1入栈的时候,发现栈顶元素2比较大,1不能直接入栈否则破坏递增性,先将2移出栈,此时1入栈。那么此时说明2和1都没左起比自身小的数字。然后数字4入栈的时候,栈顶元素1小于4,于是1就是4左起第一个小的数字。此时栈里有1和4,然后数字6入栈的时候,栈顶元素4小于6,于是4就是6左起第一个小的数字。此时栈里有1,4,6,然后数字5入栈的时候,栈顶元素6大于5不合递增性,将6移除,此时新的栈顶元素4小于5,那么4就是5左起的第一个小的数字,最终栈内数字为1,4,5。
单调递增栈:从底到定从大到小排序,解决寻找最近的比本身值大的左或右的元素;
一 单调递增栈
1.1 左侧第一个较小值
func preSmallerElementIndex(nums []int)[]int {
//asec stack to get left smaller
var res[]int
if len(nums)<1 {
return res
}
var stackIndex []int//单调增套路
res=make([]int,len(nums))
for i:=range nums {//单调增套路
for len(stackIndex)>0&&nums[i]<nums[stackIndex[len(stackIndex)-1]] {//单调增套路
stackIndex=stackIndex[0:len(stackIndex)-1]//pop//单调增套路
}
if len(stackIndex)>0 {
//first left smaller
res[i]=stackIndex[len(stackIndex)-1]
}else {
res[i]=-1
}
stackIndex=append(stackIndex,i)//单调增套路
}
return res
}
1.2 右侧第一个较小值
func NextSmallerElementIndex(nums []int)[]int {
//asec stack to get right smaller
var res[]int
if len(nums)<1 {
return res
}
var stackIndex []int//单调增套路
res=make([]int,len(nums))
for i:=range nums {//单调增套路
for len(stackIndex)>0&&nums[i]<nums[stackIndex[len(stackIndex)-1]] { //单调增套路
head := stackIndex[len(stackIndex)-1] //pop//单调增get right套路
//head is a bigger one
res[head] = nums[i] //单调增get right套路
stackIndex = stackIndex[0 : len(stackIndex)-1] //pop//单调增套路
}
//if len(stackIndex)>0 {
// //first left smaller
// res[i]=stackIndex[len(stackIndex)-1]
//}else {
// res[i]=-1
//}
stackIndex=append(stackIndex,i)//单调增套路
}
return res
}
leetcode实际例子:矩形最大面积及其变形最大矩形,链表中下一个较大节点
1.3 长度为K的最小子序列
func mostCompetitive(nums []int, k int) []int {
//最小的长度K的连续序列
var stack []int//asc stack 单调增套路
var count=len(nums)-k//most can delete
for i:=range nums {//单调增套路
for len(stack)>0&&count>0&&stack[len(stack)-1]>nums[i] {//单调增套路
stack=stack[0:len(stack)-1]//pop,单调增套路
count--
}
stack=append(stack,nums[i])//单调增套路
}
for count>0 {
//like nums = [2,4,3,3,5,4,9,6], k = 4
stack=stack[0:len(stack)-1]//pop tail is asc
count--
}
return stack
}
leetcode实际例子:最具有竞争力的子序列
二 单调递减栈
2.1 左侧第一个较大值
func preBiggerElementIndex(nums []int)[]int {
//dec stack to get left bigger
var res[]int
if len(nums)<1 {
return res
}
var stackIndex []int//单调减套路
res=make([]int,len(nums))
for i:=range nums {//单调减套路
for len(stackIndex)>0&&nums[i]>nums[stackIndex[len(stackIndex)-1]] {//单调减套路
stackIndex=stackIndex[0:len(stackIndex)-1]//pop//单调减套路
}
if len(stackIndex)>0 {
//first left bigger
res[i]=stackIndex[len(stackIndex)-1]
}else {
res[i]=-1
}
stackIndex=append(stackIndex,i)//单调减套路
}
return res
}
2.2 右侧第一个较大值
func nextBiggerElementIndex(nums []int)[]int {
//dec stack to get left bigger
var res[]int
if len(nums)<1 {
return res
}
var stackIndex []int//单调减套路
res=make([]int,len(nums))
for i:=range nums {//单调减套路
for len(stackIndex)>0&&nums[i]>nums[stackIndex[len(stackIndex)-1]] {//单调减套路
head := stackIndex[len(stackIndex)-1] //pop//单调减get right套路
res[head] = nums[i] //单调减get right套路
stackIndex=stackIndex[0:len(stackIndex)-1]//pop//单调减套路
}
//if len(stackIndex)>0 {
// //first left bigger
// res[i]=stackIndex[len(stackIndex)-1]
//}else {
// res[i]=-1
//}
stackIndex=append(stackIndex,i)//单调减套路
}
return res
}
leetcode实际例子:每日温度