在数组中想找到一个数, 左边和右边比这个数小、 且离这个数最近的位置。

 

 

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

//单调栈
public class MonotonousStack {
    public static void main(String[] args) {
        int[] arr = {3,4,2,5,6,0,1};
        int[][] darr = MonotonousStack.getNearLessNoRepeat(arr);
        MonotonousStack.printArr(darr);

        System.out.println("---------------");
        int[] arr2 = {3,4,2,5,6,0,1};
        darr = MonotonousStack.getNearLess(arr2);
        MonotonousStack.printArr(darr);
    }

    private static void printArr(int[][] darr){
        for (int i = 0; i < darr.length; i++) {
            for (int j = 0; j < darr[0].length; j++) {
                System.out.print(darr[i][j]+" ");
            }
            System.out.println();
        }
    }

    /**
     * 得到每一个位置上,左边距离这个数最近,并且小于当前数的数。
     *               右边距离这个数最近,并且小于当前数的数。
     *
     * @param  arr(不包含重复数字)
     * @return [i][0]左边, [i][1]右边
     */
    public static int[][] getNearLessNoRepeat(int[] arr){
        int[][] res = new int[arr.length][2];
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < arr.length; i++) {
            while(!stack.isEmpty() && arr[stack.peek()] > arr[i]){
                // 栈顶的数据比当前位置的数大,弹出栈顶数
                int popIndex = stack.pop();
                int leftIndex = stack.isEmpty() ? -1 : stack.peek();
                res[popIndex][0] = leftIndex;
                res[popIndex][1] = i;

            }
            stack.push(i);
        }

        while(!stack.isEmpty()){
            int popIndex = stack.pop();
            int leftIndex = stack.isEmpty() ? -1 : stack.peek();
            res[popIndex][0] = leftIndex;
            res[popIndex][1] = -1;
        }

        return res;
    }

    /**
     * 得到每一个位置上,左边距离这个数最近,并且小于当前数的数。
     *               右边距离这个数最近,并且小于当前数的数。
     *
     * @param  arr(包含重复数字)
     * @return [i][0]左边, [i][1]右边
     */
    public static int[][] getNearLess(int[] arr){
        int[][] res = new int[arr.length][2];
        // List<Integer>>放的是位置, 同样值的东西,位置压在一起
        Stack<List<Integer>> stack = new Stack<>();

        for (int i = 0; i < arr.length; i++) {
            while(!stack.isEmpty() && arr[stack.peek().get(0)] > arr[i]){
                // 底 -> 顶, 小 -> 大
                List<Integer> popIs = stack.pop();
                // 取位于下面位置的链表中,最晚加入的那个
                int leftIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size()-1);
                for(Integer popi : popIs){
                    res[popi][0] = leftIndex;
                    res[popi][1] = i;
                }
            }

            // 栈顶的值与当前值相等
            if(!stack.isEmpty() && arr[stack.peek().get(0)] == arr[i]){
                stack.peek().add(Integer.valueOf(i));
            }else{
                // 将当前值入栈
                ArrayList<Integer> list = new ArrayList<>();
                list.add(i);
                stack.push(list);
            }
        }

        while(!stack.isEmpty()){
            List<Integer> popIs = stack.pop();
            // 取位于下面位置的链表中,最晚加入的那个
            int leftIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size()-1);
            for(Integer popi : popIs){
                res[popi][0] = leftIndex;
                res[popi][1] = -1;
            }
        }

        return res;
    }
}