解决什么问题
在一个数组中,我们想知道所有的数左边离他最近比他大(小)的和右边离他最近比他大(小)的,要求时间复杂度O(N)做到。
暴力解
如果我们使用遍历的那种方法就会是O(N^2)。
单调栈解法
我们按照从栈底到栈顶从大到小的顺序来完成,压入第一个数的时候直接压入,当压入第二个数的时候首先看看他与栈顶元素的大小关系,如果它大于当前栈顶元素,那么将栈顶元素弹出,在弹出的时候就可以获得被弹出元素的信息,他左边离他最近的比他大的值是其在栈中的下一个元素,而引起它弹出的元素就是它右边比他大而且离他最近的数,如果相等那就将下标压在一起,共同结算。如果整个数组都遍历完了,栈中还有数据,栈中的数据依次弹出,因为该数据不因为某一个数而弹出,但是此时弹出的所有元素都没有右边比他大的数,而他的底下就是左边比他大的数。
如果你要找左边比他大的数和右边比他大的数,那么我们应该从栈底到栈顶从大到小,如果我们要找的是左边比他小的数和右边比他小的数,那么我们应该从栈底到栈顶从小到大。
为什么说当我们从栈中弹出一个元素的时候其下面就是左边比他大的数,而引起它弹出的就是右边比他大的数?
首先解释为什么弹出元素m在栈中的下一个元素q就是其左边最近比其大的元素,假设存在一个元素n在数组中的位置位于m和q之间,如果n小于m,那么在压入m的时候其就会被弹出,如果n大于m,那么在m元素的下面的就不会是q。所有位于q和m之间的元素都遵循以上推论。
现在解释为什么令栈顶元素弹出的元素就是位于其右边比其大的最近元素。如果两者之间存在一个比后者大的元素,那么就不会论到后者来弹出前者,中间这个元素就会将前者弹出 。
时间复杂度
因为所有的元素都入栈和出栈一次,所以时间复杂度是O(N)