1、基础知识
Stack:push() pop() peek()
小技巧:
//栈按照入栈顺序转为数组
stack.stream().mapToInt(i->i).toArray();
2、基本题型
(1)模拟
for+while、while+while
创建栈
依次入栈+计算(case语句)
class Solution036 {
public int evalRPN(String[] tokens) {
//创建栈
Stack<Integer> stack = new Stack<Integer>();
//依次入栈
for (String token : tokens) {
switch (token) {
case "+":
case "-":
case "*":
case "/":
int num1 = stack.pop();
int num2 = stack.pop();
stack.push(calculate(num1, num2, token));
break;
default:
stack.push(Integer.parseInt(token));
}
}
return stack.pop();
}
private int calculate(int num1, int num2, String operater) {
switch (operater) {
case "+":
return num1 + num2;
case "-":
return num1 - num2;
case "*":
return num1 * num2;
case "/":
return num2 / num1;
default:
return 0;
}
}
}
理清思路,分类讨论
class Solution {
public int[] asteroidCollision(int[] asteroids) {
Stack<Integer> stack = new Stack<>();
for (int num: asteroids) {
// 消耗直至停止
while (!stack.isEmpty() && stack.peek() > 0 && stack.peek() < -num) {
stack.pop();
}
// 要么碰撞消失,要么push,要么被消耗(do nothing)
if (!stack.isEmpty() && stack.peek() > 0 && stack.peek() == -num) {
stack.pop();
} else if (stack.isEmpty() || stack.peek() < 0 || num > 0) {
stack.push(num);
}
}
return stack.stream().mapToInt(i->i).toArray();
}
}
(2)单调栈
模板:
int[] nextGreaterElement(int[] nums) {
int n = nums.length;
// 存放答案的数组
int[] res = new int[n];
Stack<Integer> s = new Stack<>();
// 倒着往栈里放
for (int i = n - 1; i >= 0; i--) {
// 判定个子高矮
while (!s.isEmpty() && s.peek() <= nums[i]) {
// 矮个起开,反正也被挡着了。。。
s.pop();
}
// nums[i] 身后的更大元素
res[i] = s.isEmpty() ? -1 : s.peek();
s.push(nums[i]);
}
return res;
}
int[] nextGreaterElement(int[] nums1, int[] nums2) {
// 记录 nums2 中每个元素的下一个更大元素
int[] greater = nextGreaterElement(nums2);
// 转化成映射:元素 x -> x 的下一个最大元素
HashMap<Integer, Integer> greaterMap = new HashMap<>();
for (int i = 0; i < nums2.length; i++) {
greaterMap.put(nums2[i], greater[i]);
}
// nums1 是 nums2 的子集,所以根据 greaterMap 可以得到结果
int[] res = new int[nums1.length];
for (int i = 0; i < nums1.length; i++) {
res[i] = greaterMap.get(nums1[i]);
}
return res;
}
int[] nextGreaterElement(int[] nums) {
// 见上文
}
剩余递减序列
public static int[] dailyTemperatures(int[] temperatures) {
int[] ans = new int[temperatures.length];
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < temperatures.length; i++) {
while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
int prev = stack.pop();
ans[prev] = i - prev;
}
stack.push(i);
}
return ans;
}
模板法
int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
int[] res = new int[n];
// 这里放元素索引,而不是元素
Stack<Integer> s = new Stack<>();
/* 单调栈模板 */
for (int i = n - 1; i >= 0; i--) {
while (!s.isEmpty() && temperatures[s.peek()] <= temperatures[i]) {
s.pop();
}
// 得到索引间距
res[i] = s.isEmpty() ? 0 : (s.peek() - i);
// 将索引入栈,而不是元素
s.push(i);
}
return res;
}
public int largestRectangleArea(int[] heights) {
//栈
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) {
int height = heights[stack.pop()];
int width = i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
while (stack.peek() != -1) {
int height = heights[stack.peek()];
int width = heights.length - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
return maxArea;
}
class Solution040 {
public int largestRectangleArea(int[] heights) {
//栈
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) {
int height = heights[stack.pop()];
int width = i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
while (stack.peek() != -1) {
int height = heights[stack.pop()];
int width = heights.length - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
return maxArea;
}
public int maximalRectangle(String[] matrix) {
if(matrix.length == 0 || matrix[0].length() == 0){
return 0;
}
int[] heights = new int[matrix[0].length()];
int maxArea = 0;
for(String row : matrix){
for(int i = 0; i < row.length(); i++){
if(row.charAt(i) == '0'){
heights[i] = 0;
}else {
heights[i]++;
}
}
maxArea = Math.max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
}
如何处理环形数组
int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int[] res = new int[n];
Stack<Integer> s = new Stack<>();
// 数组长度加倍模拟环形数组
for (int i = 2 * n - 1; i >= 0; i--) {
// 索引 i 要求模,其他的和模板一样
while (!s.isEmpty() && s.peek() <= nums[i % n]) {
s.pop();
}
res[i % n] = s.isEmpty() ? -1 : s.peek();
s.push(nums[i % n]);
}
return res;
}
LeetCode同题型
模仿
class StockSpanner {
private List<Integer> arr;
private int i;
private Stack<Integer> stack;
public StockSpanner() {
arr = new ArrayList<>();
stack = new Stack<>();
i = -1;
stack.push(-1);
}
public int next(int price) {
arr.add(price);
i++;
while (stack.peek() != -1 && price >= arr.get(stack.peek())) {
stack.pop();
}
int last = stack.peek();
stack.push(i);
return i - last;
}
}
class Solution {
public String removeKdigits(String num, int k) {
Deque<Integer> stack = new LinkedList<>();
for (int i = 0; i < num.length(); i++) {
int cur = num.charAt(i) - '0';
while (k > 0 && !stack.isEmpty() && cur < stack.peekLast()) {
stack.removeLast();
k--;
}
stack.offerLast(cur);
}
for (int i = 0; i < k; i++) {
stack.removeLast();
}
if (stack.isEmpty()) {
return "0";
}
StringBuilder ret = new StringBuilder();
boolean leadingZero = true;
while (!stack.isEmpty()) {
int digit = stack.removeFirst();
if (leadingZero && digit == 0) {
continue;
}
leadingZero = false;
ret.append(digit);
}
return ret.length() == 0 ? "0" : ret.toString();
}
}
法一:动态规划
法二:单调栈
法三:双指针
单调栈:
class Solution {
public int trap(int[] height) {
Stack<Integer> stack = new Stack<Integer>();
int res = 0;
for (int i = 0; i < height.length; i++) {
while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
int top = stack.pop();
if (stack.isEmpty()) {
continue;
}
int left = stack.peek();
int width = i - left - 1;
int minHeight = Math.min(height[i], height[left]) - height[top];
res += minHeight * width;
}
stack.push(i);
}
return res;
}
}
将链表中的数据存进动态数组里,转化为模板题型
class Solution {
public int[] nextLargerNodes(ListNode head) {
Stack<Integer> stack = new Stack<Integer>();
List<Integer> array = new ArrayList<Integer>();
while (head != null) {
array.add(head.val);
head = head.next;
}
int[] res = new int[array.size()];
for (int i = 0; i < array.size(); i++) {
while (!stack.isEmpty() && array.get(i) > array.get(stack.peek())) {
int last = stack.pop();
res[last] = array.get(i);
}
stack.push(i);
res[i] = 0;
}
return res;
}
}
法一:Kanade 算法,基于动态规划(53题)
法二:前缀和+单调队列
class Solution {
public int[] canSeePersonsCount(int[] heights) {
int[] ans = new int[heights.length];
Stack<Integer> stack = new Stack<>();
for (int i = heights.length - 1; i >= 0; i--) {
while (!stack.isEmpty() && heights[i] > heights[stack.peek()]) {
stack.pop();
ans[i]++;
}
ans[i] += stack.isEmpty()? 0 : 1;
stack.push(i);
}
return ans;
}
}