数据结构-单调栈 leetcode 下一个更大的数2
由leetcode题目引入:
刷题时看到这道题,第一反应使用循环数组暴力解题了,附上代码
暴力解题代码
public static int[] nextGreaterElements(int[] nums) {
int[] res = new int[nums.length];
Arrays.fill(res,-1);
int j;
int index;
for (int i = 0; i < nums.length; i++) {
j = i + 1;
while ((index = (j % nums.length)) != i){
if (nums[index] > nums[i]){
res[i] = nums[index];
break;
}
j++;
}
}
return res;
}
提交后发现速度较慢 查看题解后了解到单调栈这种数据结构,接下来了解一下单调栈
什么是单调栈
简而言之,就是栈中的元素时单调有序的
具体根据单调递增和单调递减又可以分为单调递增栈和单调递减栈(这里的单调是指pop出元素的顺序)
了解到以上概念之后,就动手实现一个单调栈
模拟单调栈流程:
- 给定数据:7 6 4 9
- 使用单调栈解决 流程模拟
- 遍历7 此时栈为空 ,将7入栈 此时栈内元素为7
- 遍历6 此时栈顶元素为7, 6<7 将6入栈 此时栈内元素为7 6
- 遍历4 此时栈顶元素为6, 4<6 将4入栈 此时栈内元素为7 6 4
- 遍历9 此时栈顶元素为9, 9>4 不满足入栈条件
- 循环处理 将4 出栈 此时栈内元素为7 6
- 将6 出栈 此时栈内元素为7
- 将7 出栈 此时栈内元素为空
- 栈为空 满足入栈条件 将9入栈 此时栈内元素为9
单调栈代码
package stack;
/**
* 单调栈实现 单调递增实现(每次取出元素先取出最小的元素 待元素全部取出是递增的方式取出的)
*
*/
public class MonStack {
private Node head;
private int length;
public MonStack(){
head = new Node(0,null);
length = 0;
}
public void push(int element){
while (!isEmpty() && peek() < element){
pop();
}
length++;
Node node = new Node(element, head.next);
head.next = node;
}
public int pop(){
if (isEmpty())
return -1;
length--;
Node node = head.next;
head.next = node.next;
return node.element;
}
public int peek(){
return head.next.element;
}
public boolean isEmpty(){
return length == 0;
}
private class Node{
private int element;
private Node next;
public Node(int element,Node next){
this.element = element;
this.next = next;
}
}
public static void main(String[] args) {
MonStack monStack = new MonStack();
monStack.push(7);
monStack.push(6);
monStack.push(4);
monStack.push(3);
monStack.push(12);
System.out.println(monStack.pop());
System.out.println(monStack.pop());
System.out.println(monStack.pop());
}
}
应用单调栈解决该题
/**
* 优化
* 根据题意的性质可知 如果一个数找到了他的下一个更大元素 那么在该更大元素之前和该数之后的数(二者之间的数)的下一个更大元素都是该更大元素
* 例: 7 6 4 9
* 7之后的大数为9 那么在7之后 9之前的所有数他的大数都是9
* 使用单调栈解决 流程模拟
* 遍历7 此时栈为空 将7入栈
* 遍历6 此时栈顶元素为7 6<7 将6入栈
* 遍历4 此时栈顶元素为6 4<6 将4入栈
* 遍历9 此时栈顶元素为9 9>4 不满足入栈条件
* 循环处理 将4 出栈 并设置4的下一个更大元素为9
* 将6 出栈 并设置6的下一个更大元素为9
* 将7 出栈 并设置7的额下一个更大元素为9
* 此时栈为空 将9入栈
* 继续遍历 for循环结束也没有找到比9更大的元素 直接结束即可
* 可以使用单调栈来解决
* @param nums
* @return
*/
public static int[] nextGreaterElements_new(int[] nums) {
int[] res = new int[nums.length];
Arrays.fill(res,-1);
Deque<Integer> stack = new LinkedList();
// 循环nums.length*2 - 1 的原因:因为本题是循环查找 但却最多循环不会超过两次 所以直接循环两次即可
// 如果需要多次循环 则直接取模即可
for (int i = 0; i < nums.length*2 - 1; i++) {
// 单调栈入栈的规则是 栈不为空 && 栈顶元素大于要入栈的元素
// 如果不满足该条件则将栈顶元素移除 以满足上述条件
// 简而言之,入栈的元素都是比第一个入栈元素值小的元素 只不过这里比较的是元素值的大小 入栈的是该元素的下标
while (!stack.isEmpty() && nums[stack.peek()] < nums[i%nums.length]){
res[stack.pop()] = nums[i % nums.length];
}
stack.push(i % nums.length);
}
return res;
}