一)单调栈简介
栈的特性是“先进后出,后进先出”
单调栈:在栈的基础上,单调递增或单调递减的一种特殊栈。
基本原理:当一个元素进栈时,用进栈元素和栈顶元素比较,当进栈元素大于等于或小于栈顶元素时,先把栈顶元素进行出栈操作,直到栈顶元素小于进栈元素,最后把进栈元素push进栈。
单调栈步骤解析:
例如:有一组数据[7, 3, 8, 5, 6, 4],从左往右依次进栈。
递增单调栈:
第i步 | 栈操作 | 栈中结果 |
第1步 | 7进栈 | [7] |
第2步 | 3进栈 | [7, 3] |
第3步 | 8进栈,3出栈,7出栈 | [8] |
第4步 | 5进栈 | [8, 5] |
第5步 | 6进栈,5出栈 | [8, 6] |
第6步 | 4进栈 | [8, 6, 4] |
递减单调栈:
第i步 | 栈操作 | 栈中结果 |
第1步 | 7进栈 | [7] |
第2步 | 3进栈,7出栈 | [3] |
第3步 | 8进栈 | [3, 8] |
第4步 | 5进栈,8出栈 | [3, 5] |
第5步 | 6进栈 | [3, 5, 6] |
第6步 | 4进栈,6出栈,5出栈 | [3, 4] |
二)单调栈
1)递增单调栈源码
/**
* 递增单调栈
* @param nums
* @return
*/
public static Stack<Integer> increaseByDegreesStack(int[] nums) {
Stack<Integer> stack = new Stack<Integer>();
if (nums != null) { // 元素不能为空
for (int i = 0; i < nums.length; i++) {
int number = nums[i];
while (!stack.empty() && number >= stack.peek()) { // 先判断进栈元素和栈顶元素的大小
stack.pop(); // 元素大于栈顶元素, 就一直出栈
}
stack.push(number); // 把元素入栈
}
}
return stack;
}
2)递减单调栈源码
/**
* 递减单调栈
* @param nums
* @return
*/
public static Stack<Integer> degressionStack(int[] nums) {
Stack<Integer> stack = new Stack<Integer>();
if (nums != null) { // 元素不能为空
for (int i = 0; i < nums.length; i++) {
int number = nums[i];
while (!stack.empty() && number < stack.peek()) { // 先判断进栈元素和栈顶元素的大小
stack.pop(); // 元素大于栈顶元素, 就一直出栈
}
stack.push(number); // 把元素入栈
}
}
return stack;
}
三)单调栈习题
标题:给一个数组,判断数组中的一个元素从左往右走,至少往右走多少步,才能遇到一个比自己大的元素,存在则返回步数,不存在则返回0
例如:
int[] steps = {7, 3, 8, 5, 6, 4};
返回:[2, 1, 0, 1, 0, 0]
源码:
/**
* 给一个数组,判断数组中的一个元素从左往右走,至少往右走多少步,才能遇到一个比自己大的元素,存在则返回步数,不存在则返回0
* @param nums
* @return
*/
public static int[] stepNumber(int[] nums) {
if (nums == null) {
return null;
}
Stack<Integer> stack = new Stack<Integer>();
int[] dp = new int[nums.length]; // 临时数组,记录每一个元素的步数
for (int i = 0; i < nums.length; i++) {
while (!stack.empty() && nums[i] > nums[stack.peek()]) { // 比元素大
dp[stack.peek()] = i - stack.peek(); // 记录步数
stack.pop(); // 栈顶元素出栈
}
stack.push(i); // 进栈
}
return dp;
}
识别二维码关注个人微信公众号
本章完结,待续、欢迎转载!
本文说明:该文章属于原创,如需转载,请标明文章转载来源!