【剑指offer2】 chap6 栈

1、基础知识

Stack:push()   pop()    peek()

小技巧:

//栈按照入栈顺序转为数组
stack.stream().mapToInt(i->i).toArray();

2、基本题型

(1)模拟

for+while、while+while

剑指 Offer II 036. 后缀表达式

创建栈

依次入栈+计算(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;
        }
    }
}

剑指 Offer II 037. 小行星碰撞

理清思路,分类讨论

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;
}

 496. 下一个更大元素 I

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) {
    // 见上文
}

剑指 Offer II 038. 每日温度

剩余递减序列

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;
}

剑指 Offer II 039. 直方图最大矩形面积

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;
}

剑指 Offer II 040. 矩阵中最大的矩形

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;
    }
}

如何处理环形数组

503. 下一个更大元素 II

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同题型

901. 股票价格跨度

模仿 

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;
    }
}

402. 移掉 K 位数字

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();
    }
}

42. 接雨水

法一:动态规划

法二:单调栈

法三:双指针

单调栈:

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;
    }
}

1019. 链表中的下一个更大节点

 将链表中的数据存进动态数组里,转化为模板题型

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;
    }
}

918. 环形子数组的最大和

法一:Kanade 算法,基于动态规划(53题)

法二:前缀和+单调队列

 1944. 队列中可以看到的人数

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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值