【备战字节面试】算法特训-栈/单调栈

204 阅读1分钟

简单粗暴,记录备战过程,持续更新

单调栈

是栈的一种类型,但是有些自己的特性; 特性如下:

  • 要求栈中的元素是单调递增或者单调递减

pop时元素是递增,即单调递增栈,pop时元素是递减,即单调递减栈

示例:栈内元素(左栈底,右栈顶),[1,2,3,4], 出栈后4,3,2,1, 即单调递增栈;

适用场景

使用单调栈场景是求解下一个大于 xxx或者下一个小于 xxx这种题目。所有当你有这种需求的时候,就应该想到单调栈。

实战

实战1,leetcode 84. 柱状图中最大的矩形

public class Lee0084 {

    public static void main(String[] args) {
        int[] arr = {2, 3, 5, 6, 1};
        System.out.println(largestRectangleArea(arr));
    }

    public static int largestRectangleArea(int[] heights) {
        int ans = 0;
        Deque<Integer> stack = new ArrayDeque<>();

        // 增加哨兵节点
        int[] tmpHeights = new int[heights.length + 1];
        for (int i = 0, len = heights.length; i < len; i++) {
            tmpHeights[i] = heights[i];
        }
        tmpHeights[heights.length] = 0;
        heights = tmpHeights;
        stack.addLast(-1);
        for (int i = 0, len = heights.length; i < len; i++) {
            // 空 或 大于栈顶,进栈
            if (stack.getLast() == -1 || heights[stack.getLast()] < heights[i]) {
                stack.addLast(i);
            }
            // 小于等于,出栈
            else {
                while ((stack.getLast() > -1 && heights[stack.getLast()] >= heights[i])) {
                    // 高 乘 宽(右非大于下标 - 左非大于下标 - 1)
                    int temp = heights[stack.removeLast()] * (i - stack.getLast() - 1);
                    ans = Math.max(ans, temp);
                }
                stack.addLast(i);
            }
        }
        return ans;
    }
}

实战2,leetcode 42.接雨水

public class Lee0042 {

    public static void main(String[] args) {
        int[] arr = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
        System.out.println(trap(arr));
    }

    public static int trap(int[] height) {
        int sum = 0;
        Deque<Integer> stack = new ArrayDeque<>();
        for (int i = 0, len = height.length; i < len; i++) {
            // 大于,出栈
            while (!stack.isEmpty() && height[stack.getLast()] < height[i]) {
                int topHeight = stack.removeLast();
                if (stack.isEmpty()) {
                    break;
                }
                int distance = i - stack.getLast() - 1;
                sum += distance * (Math.min(height[i], height[stack.getLast()]) - height[topHeight]);
            }
            stack.addLast(i);
        }
        return sum;
    }
}

实战3,leetcode 496. 下一个更大元素 I

import java.util.*;

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        Map<Integer,Integer> map = new HashMap<>();
        Deque<Integer> stack = new ArrayDeque<>();
        for(int i = 0,len = nums2.length ; i< len ; i++){
            while(!stack.isEmpty() && stack.getLast() < nums2[i]){
                map.put( stack.removeLast(),nums2[i]);
            }
            stack.addLast(nums2[i]);
        }
        for(int i = 0, len = nums1.length ; i< len ; i++){
            nums1[i] = map.getOrDefault(nums1[i],-1);
        }
        return nums1;
    }
}

实战4,leetcode, 739. 每日温度

import java.util.*;

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        Deque<Integer> stack = new ArrayDeque<>();
        for(int i = 0 ; i < temperatures.length ; i++){
            while(!stack.isEmpty() && temperatures[stack.getLast()] < temperatures[i]){
                temperatures[stack.getLast()] =  i - stack.removeLast();
            }
            stack.addLast(i);
        }
        while(!stack.isEmpty()){
             temperatures[stack.removeLast()] = 0;
        }
        return temperatures;
    }
}

实战5,leetcode 316. 去除重复字母

import java.util.*;

class Solution {
    public String removeDuplicateLetters(String s) {
        int [] lastIndex = new int[26];
        char[] charArr = s.toCharArray();
        for(int i= 0 ; i < charArr.length ; i++){
            lastIndex[charArr[i]-'a'] = i;
        }
        Boolean[] inStack = new Boolean[26];
        Deque<Character> stack = new ArrayDeque<>();
        for(int i= 0; i < charArr.length ; i++){
            // 栈顶 > 当前 , 且后面还有, 则出栈
            while( !stack.isEmpty() && stack.getLast() > charArr[i] && i < lastIndex[stack.getLast() - 'a']){
                inStack[stack.getLast() - 'a'] = false;
                stack.removeLast();
            }
            // 空 
            inStack[charArr[i] - 'a'] = true;
            stack.addLast(charArr[i]);
        } 
        StringBuilder ret = new StringBuilder();
        while(!stack.isEmpty() ){
             ret.append(stack.removeFirst());
        }
       return ret.toString();
    }
}

实战6 155. 最小栈

class MinStack {
    
    private Deque deque ;
    private Queue priorityQueue ;

    public MinStack() {
        deque = new ArrayDeque<Integer>();
        priorityQueue = new PriorityQueue<Integer>();
    }
    
    public void push(int val) {
        deque.addLast(val);
        priorityQueue.add(val);
    }
    
    public void pop() {
        int val = (Integer)deque.removeLast();
        priorityQueue.remove(val);
    }
    
    public int top() {
        return (Integer)deque.getLast();
    }
    
    public int getMin() {
        return (Integer)priorityQueue.peek();
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(val);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

实战7 503. 下一个更大元素 II

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int len = nums.length;
        int[] ans = new int[len];
        Arrays.fill(ans,-1);
        ArrayDeque<Integer> stack = new ArrayDeque<>(len);
        for(int i = 0 ; i < 2*len - 1 ; i++){
            while(!stack.isEmpty() && nums[stack.getLast()] < nums[i % len]){
                int val = stack.removeLast();
                ans[val] = nums[i % len];
            }
            stack.addLast(i % len);
        }
        return ans;
    }
}

实战8 20. 有效的括号

class Solution {
    public boolean isValid(String s) {
        int len = s.length();
        ArrayDeque<Character> stack = new ArrayDeque<>(len);

        for(int i = 0; i < len; i++){
            if(stack.isEmpty()){
                stack.addLast(s.charAt(i));
            }else{
                char tmp = stack.getLast();
                if(tmp == '(' && s.charAt(i) == ')'){
                    stack.removeLast(); 
                }else if (tmp == '{' && s.charAt(i) == '}'){
                    stack.removeLast();
                }else if (tmp == '[' && s.charAt(i) == ']'){
                    stack.removeLast();
                }else{
                    stack.addLast(s.charAt(i));
                }
            }
        }
        return stack.isEmpty() ? true : false;

    }
}

实战9 71. 简化路径

class Solution {
    public String simplifyPath(String path) {
        String[] names = path.split("/");
        ArrayDeque<String> stack = new ArrayDeque<>(names.length);
        for(String name : names){
            if("..".equals(name)){
                if(!stack.isEmpty()){
                    stack.removeLast();
                }
            }else if(name.length() > 0 && !".".equals(name)){
                stack.addLast(name);
            }
        }
        StringBuilder sb = new StringBuilder();
        if(stack.isEmpty()){
            sb.append("/");
        }
        while(!stack.isEmpty()){
            sb.append("/");
            sb.append(stack.removeFirst());
        }
        return sb.toString();
    }
}