借助单调栈实现查找数组中每个数左边/右边第一个比它大/小的元素下标 Java模板

单调栈模板

主要参考:https://www.bilibili.com/video/BV1my4y1Z7jj/

四种情况代码模板,分别对应查找数组中每个数左边/右边第一个比它大/小的元素下标。

package test;

import java.util.ArrayDeque;
import java.util.Deque;

class MonoStack{
    public static void MonoStackFunc(int[] arrs) {
        int n = arrs.length;

        // 1.寻找左侧第一个比当前元素大的元素 下标
        int[] leftMax = new int[n];
        Deque<Integer> st = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            int x = arrs[i];
            // 构造单调递增栈
            while(!st.isEmpty() && x >= arrs[st.peek()]){
                st.pop();
            }
            // stack栈顶 存的都是最右、最大的值 下标
            leftMax[i] = st.isEmpty() ? -1:st.peek();
            st.push(i);
        }

        // 2.寻找左侧第一个比当前元素小的元素 下标
        int[] leftMin = new int[n];
        st.clear();
        for (int i = 0; i < n; i++) {
            int x = arrs[i];
            while (!st.isEmpty() && x <= arrs[st.peek()]) {
                st.pop();
            }
            leftMin[i] = st.isEmpty() ? -1 : st.peek();
            st.push(i);
        }

        // 3.1.寻找右侧第一个比当前元素大的元素 下标
        int[] rightMax = new int[n];
        st.clear();
        for (int i = 0; i < n; i++) {
            int x= arrs[i];
            // stack从栈顶开始,如果i为比较大的数的下标,则找到了自己要的结果
            while(!st.isEmpty() && x > arrs[st.peek()]){
                rightMax[st.peek()] = i;
                st.pop();
            }
            // 找不到的先存起来
            st.push(i);
        }
        // 没找到的默认设置为长度n
        while(!st.isEmpty()){rightMax[st.pop()] = n;}

        // 3.2.寻找右侧第一个比当前元素大的元素 下标【写法2】
        int[] rightMax2 = new int[n];
        st.clear();
        for (int i = n-1; i >= 0; i--) {
            int x= arrs[i];
            while(!st.isEmpty() && x >= arrs[st.peek()]){
                st.pop();
            }
            rightMax2[i] = st.isEmpty()? n:st.peek();
            st.push(i);
        }

        // 4.1.寻找右侧第一个比当前元素小的元素 下标
        int[] rightMin = new int[n];
        st.clear();
        for (int i = 0; i < n; i++) {
            int x = arrs[i];
            while(!st.isEmpty() && x < arrs[st.peek()]){
                rightMin[st.peek()] = i;
                st.pop();
            }
            st.push(i);
        }
        while(!st.isEmpty()){rightMin[st.pop()] = n;}

        // 4.2.寻找右侧第一个比当前元素小的元素 下标【写法2】
        int[] rightMin2 = new int[n];
        st.clear();
        for (int i = n-1; i >= 0; i--) {
            int x= arrs[i];
            while(!st.isEmpty() && x <= arrs[st.peek()]){
                st.pop();
            }
            rightMin2[i] = st.isEmpty()? n: st.peek();
            st.push(i);
        }

        return;
    }

    public static void main(String[] args) {
        MonoStackFunc(new int[]{2,1,5,6,2,3});
        return;
    }
}

力扣 739. 每日温度

该问题相当于要先获得数组中每个数右边第一个比它大的元素下标,因此可以用3.1或3.2的方式解决。下面给出两种解法。

    // 3.1
    public int[] dailyTemperatures(int[] temperatures) {
        int n = temperatures.length;

        int[] res = new int[n];
        Deque<Integer> st = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            int x = temperatures[i];
            while(!st.isEmpty() && x > temperatures[st.peek()]){
                res[st.peek()] = i - st.peek();
                st.pop();
            }
            st.push(i);
        }

        return res;
    }
    
    // 3.2
    public int[] dailyTemperatures(int[] temperatures) {
        int n = temperatures.length;

        int[] res = new int[n];
        Deque<Integer> st = new ArrayDeque<>();
        for (int i = n-1; i >= 0; i--) {
            int x = temperatures[i];
            while(!st.isEmpty() && x >= temperatures[st.peek()]){
                st.pop();
            }
            res[i] = st.isEmpty() ? 0 : st.peek() - i;
            st.push(i);
        }

        return res;
    }

力扣 84. 柱状图中最大的矩形

主要参考灵茶山艾府的代码。

其中寻找右边第一个比他小的下标实现了2种方式。

    public int largestRectangleArea(int[] heights) {
        int n = heights.length;

        int[] left = new int[n];
        Deque<Integer> st = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            int x = heights[i];
            while(!st.isEmpty() && x <= heights[st.peek()]){
                st.pop();
            }
            left[i] = st.isEmpty()? -1:st.peek();
            st.push(i);
        }

        int[] right = new int[n];
        st.clear();
        
        // 4.2 寻找右侧第一个比当前元素小的元素 下标
        /*
        for (int i = 0; i < n; i++) {
            int x = heights[i];
            while(!st.isEmpty() && x < heights[st.peek()]){
                right[st.peek()] = i;
                st.pop();
            }
            st.push(i);
        }
        while(!st.isEmpty()){right[st.pop()] = n;}
        */
        
        // 4.1
        for (int i = n-1; i >= 0; i--) {
            int x = heights[i];
            while(!st.isEmpty() && x <= heights[st.peek()]){
                st.pop();
            }    
            right[i] = st.isEmpty()? n:st.peek();
            st.push(i);
        }

        int res = 0;
        for (int i = 0; i < n; i++) {
            int width = right[i] - left[i] -1;
            res = Math.max(res, heights[i] * width);
        }

        return res;
    }

参考文献

理论介绍:
https://www.bilibili.com/video/BV1VN411J7S7/

各种情况分析:
https://blog.csdn.net/zy_dreamer/article/details/131036101

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
可以使用单调栈来解决这个问题。具体实现如下: ```c #include <stdio.h> #include <stdlib.h> typedef struct { int value; int index; } Pair; typedef struct { Pair *data; int top; int size; } Stack; Stack *createStack(int size) { Stack *stack = (Stack *)malloc(sizeof(Stack)); stack->data = (Pair *)malloc(sizeof(Pair) * size); stack->top = -1; stack->size = size; return stack; } void push(Stack *stack, Pair pair) { if (stack->top == stack->size - 1) { return; } stack->top++; stack->data[stack->top] = pair; } Pair pop(Stack *stack) { if (stack->top == -1) { Pair pair = {-1, -1}; return pair; } Pair pair = stack->data[stack->top]; stack->top--; return pair; } void nextGreaterElement(int *nums, int numsSize, int *result) { Stack *stack = createStack(numsSize); for (int i = 0; i < numsSize; i++) { Pair pair = {nums[i], i}; while (stack->top != -1 && stack->data[stack->top].value < nums[i]) { Pair p = pop(stack); result[p.index] = i; } push(stack, pair); } while (stack->top != -1) { Pair p = pop(stack); result[p.index] = -1; } free(stack->data); free(stack); } int main() { int nums[] = {3, 1, 4, 2}; int numsSize = sizeof(nums) / sizeof(int); int *result = (int *)malloc(sizeof(int) * numsSize); nextGreaterElement(nums, numsSize, result); for (int i = 0; i < numsSize; i++) { printf("%d ", result[i]); } printf("\n"); free(result); return 0; } ``` 这个程序使用了单调栈到每个元素右边第一个比它大的元素。具体来说,我们从左到右遍历数组,对于每个元素,我们将它和它的下标打包成一个 Pair 结构体,然后将这个 Pair 入栈。如果栈顶元素的值比当前元素小,那么我们就弹出栈顶元素,并将它的下标作为当前元素右边第一个比它大的元素下标。如果栈为空,说明当前元素右边没有比它大的元素,我们将它的下标设为 -1。最后,我们遍历一遍栈,将剩余的元素下标设为 -1。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值