前言
栈(stack)是一个十分常见与简单的数据结构,讲究先进后出。
Java中栈的方法有
push() 将元素放入栈顶
pop() 将栈顶元素推出栈
peek() 查看栈顶元素
isEmpty() 判断栈是否为空 为空返回true 不为空返回false
栈常解决的问题(Next Number)
可解决问题1
给你一个数组要求你返回一个等长的数组,返回的数组中每个元素为对应之前数组比它大的最近一个元素,如果没有就返回-1,这样说可能不太明白,直接上例子
给你一个数组[2,7,1,4] 要求你返回[7,-1,4,-1]
解释:数组元素2后边比它大的第一个元素为7;7后边比它大的第一个元素没有找到为-1;1后边比它大的第一个元素是4;4后边没有比它大的元素返回为-1;
我们普遍想到的是暴力求解,O(n^2)的时间复杂的常常是超时的。
我们可以想一个这样的思路:从后往前遍历,用栈来存储当前元素右边比他大的最近一个元素。如果栈顶元素stack.peek()<=nums[i],我们就不断推栈,直到找到比nums[i]大的元素,没有找到为-1
class Solution {
public static int[] findNextElement(int[] nums) {
//定义一个等长的数组
int[] result = new int[nums.length];
Stack<Integer> stack = new Stack<>();
for (int i = nums.length-1; i >=0 ; i--) {
//如果栈顶元素小于当前元素就不断推栈
while(!stack.isEmpty()&&stack.peek()<nums[i]){
stack.pop();
}
result[i]=stack.isEmpty()?-1:stack.peek();
stack.push(nums[i]);
}
return result;
}
}
可解决问题2
给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false
听起来好像很简单,但实际做起来需要费一些功夫。我们参考原先模型的核心代码
for (int i = nums.length-1; i >=0 ; i--) {
//这里略微做了改动,stack中存放的是数组的下标索引
while(!stack.isEmpty()&&nums[stack.peek()]<=nums[i]){
stack.pop();
}
stack.push(i);
}
我们观察当nums[stack.peek()]<=nums[i],
我们往常的思路是去除栈内比nums[i]小的数。
我们换一种思路,此时想想以下我们是不是找到了num[j]>num[k]的情况, 我们把num[i]理解为题目中要找的nums[j],把栈内推出的数理解为k ,而我们不断推出的数,最后一个为比nums[j]小的最大一个数,我们此时只需要在nums向前遍历的途中找到一个nums[i],便可满足nums[i]<nums[k]<nums[j]
public boolean find132pattern(int[] nums) {
//栈中存放数组的下标索引
Stack<Integer> stack = new Stack<>();
Integer k =-1;
for (int i = nums.length-1; i >= 0; i--) {
if(k!=-1&&nums[i]<nums[k])return true;
while(!stack.isEmpty()&&nums[stack.peek()]<nums[i]){
//此时我们找到了左边元素大于右边的情况,我们可以将
//当前元素nums[i] 理解为题目中第一大元素3 nums[j]
//我们推出的栈内元素 理解为题目中中等大元素2 nums[k]
k = stack.pop();
//现在我们只需在i向前遍历中找到nums[i]<nums[k]便可满足条件
}
stack.push(i);
}
return false;
}