数据结构-单调栈求出子数组最大值

给定一个只包含正数的数组arr, arr中任何一个子数组sub,一定都可以算出(sub累加和)*(sub中的最小值)是什么,那么所有子数组中,这个值最大是多少?


import java.util.Stack;

public class AllTimesMinToMax {
    public static void main(String[] args) {
        //int[] arr = {12,4,5,2,2,5,6,7,8,9,1,6,4,1,4,7,8,9};
        //int[] arr = {1,2,2,2,2,2,2,2,2,1};
        for (int i = 0; i < 1000; i++) {
            int[] arr = generateRondomArray();
            int r1 = max1(arr);
            int r2 = max2(arr);

            if(r1 != r2){
                System.out.println("false");
                break;
            }else{
                System.out.println(i +" "+arr.length+" "+r1+" "+r2+" "+" true");
            }
        }

        //System.out.println("true");
    }

    // 暴力循环
    public static int max1(int[] arr){
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) {
            for (int j = i; j < arr.length; j++) {
                int min = Integer.MAX_VALUE;
                int sum = 0;
                for (int k = i; k <= j; k++) {
                    sum += arr[k];
                    min = Math.min(min, arr[k]);
                }

                max = Math.max(max, sum * min);
            }
        }

        return max;
    }

    // 通过单调栈
    public static int max2(int[] arr){
        int size = arr.length;
        int[] sums = new int[size];
        sums[0] = arr[0];
        // 预处理一个前缀数组和
        for (int i = 1; i < arr.length; i++) {
            sums[i] = sums[i-1]+arr[i];
        }

        // 以每一个索引i的数arr[i]作为最小值
        int max = Integer.MIN_VALUE;
        Stack<Integer> stack = new Stack<Integer>();
        for (int i = 0; i < arr.length; i++) {
            int leftIndex = 0;
            while(!stack.isEmpty() && arr[stack.peek()] >= arr[i]){
                int popIndex = stack.pop();
                // 此时 arr[popIndex]是数组区间(leftIndex,i)中的最小值
                leftIndex = stack.isEmpty() ? -1 : stack.peek();
                // 5,1,2,7,6,4,3,8,2,9
                int sum = sums[i-1] - (leftIndex==-1 ? 0 : sums[leftIndex]);
                max = Math.max(max, sum * arr[popIndex]);
            }

            stack.push(i);
        }

        while(!stack.isEmpty()){
            int popIndex = stack.pop();
            int leftIndex = stack.isEmpty() ? -1 : stack.peek();
            int sum = sums[size-1] - (leftIndex==-1 ? 0 : sums[leftIndex]);
            max = Math.max(max, sum * arr[popIndex]);
        }

        return max;
    }

    public static int[] generateRondomArray(){
        int[] arr = new int[(int)(Math.random() * 20) + 10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int)(Math.random() * 101);
        }
        return arr;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值