单调栈结构

题目描述

给定一个不含有重复值的数组 arr,找到每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置。返回所有位置相应的信息。

输入描述:

第一行输入一个数字 n,表示数组 arr 的长度。
以下一行输出 n个数字,表示数组的值。

输出描述:

输出n行,每行两个数字 L 和 R,如果不存在,则值为-1,下标从0开始。

示例1

输入
7
3 4 1 5 6 2 7

输出
-1 2
0 2
-1 -1
2 5
3 5
2 -1
5 -1

分析

要找到数组中每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置,我们需要借助栈来实现,该栈保存数组的下标,且需要保持从栈顶到栈底的下标idx所对应的arr[idx]由大到小。当然,如果我们是要找到数组中每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 大的位置,那么我们就需要保持栈从栈顶到栈底的下标idx所对应的arr[idx]由小到大的特性。

接下来我们来使用单调栈来求得数组arr[3 4 1 5 6 2 7]中每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置:

当数组遍历到0号位时,发现栈为空,那么就直接将下标0压入栈中,如下图所示:
单调栈结构_第1张图片
当数组遍历到1号位时,发现arr[1]大于栈顶元素即数组的坐标0所对应的数组元素3,那么直接将下标1压入栈中,如下图示:
单调栈结构_第2张图片
接着数组遍历到2号位时,发现arr[2]小于栈顶元素即数组的下标1所对应的数组元素4,那么直接弹出栈顶元素1,那么 1 位置左边和右边离 1 位置最近且值比 arr[1] 小的位置分别为新的栈顶0和当前的i = 2,并记录在结果数组中。若当前位置i其左边和右边不存在比arr[i]最近且比其小元素,那么就默认位置为-1。重复上述过程,直到栈为空或者arr[2]大于栈顶下标所对应的数组元素时直接压入i。该过程的结果如下图示:
单调栈结构_第3张图片
当数组从3号位遍历到4号时,会将数组元素5和6所对应的下标压入栈中。如下图示:
单调栈结构_第4张图片
当数组遍历到5号位时,发现arr[5]小于栈顶中元素4所对应的数组元素6,那么弹出栈顶元素并记录其左右比arr[5]小且最近的元素的下标。同理,新的栈顶也会被弹出。然后压入元素2的下标5。如下图示:
单调栈结构_第5张图片
当数组遍历到6号位时,发现arr[6]大于栈顶元素5所对应的arr[5],即2,那么直接压入下标6。自此,数组遍历结束,栈和结果数组的状态如下图所示:
单调栈结构_第6张图片
接着,我们循环的弹出栈顶元素idx,并记录arr[idx]的左边和右边最近且比arr[idx]小的元素下标,我们可以发现左边最近且比arr[idx]小的元素的下标为新的栈顶元素(若不存在则为-1),右边最近且比arr[idx]小的元素的下标不存在,即为-1。最后我们得到如下结果数组:
单调栈结构_第7张图片

代码
import java.util.*;

public class Main {
	// 核心代码
	public static int[][] getNearLessNoRepeat(int[] arr) {
		ArrayDeque<Integer> stack = new ArrayDeque<>();
		int[][] res = new int[arr.length][2];
		for (int i = 0; i < arr.length; i++) {
			while (!stack.isEmpty() && arr[i] < arr[stack.peek()]) {
				int top = stack.pop();
				int leftIdx = stack.isEmpty() ? -1 : stack.peek();
			    res[top][0] = leftIdx;
                res[top][1] = i;
			}
			stack.push(i);
		}
		while (!stack.isEmpty()) {
			int top = stack.pop();
            int leftIdx = stack.isEmpty() ? -1 : stack.peek();
			res[top][0] = leftIdx;
            res[top][1] = -1;
		}
		return res;
	}

	// for test
	public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
		int[][] res = getNearLessNoRepeat(arr);

		for (int i = 0; i < res.length; i++) {
			System.out.println(res[i][0] + " " + res[i][1]);
		}
	}
}

你可能感兴趣的:(单调栈)