No.907 Sum of Subarray Minimums

907. 子数组的最小值之和 - 力扣(LeetCode) (leetcode-cn.com)

 思路参考:【LeetCode】907. Sum of Subarray Minimums_哔哩哔哩_bilibili

做过较多类似题目的话很容易就想到枚举每个数字将其作为最小数时计算其所包含的子数组个数,要计算这样的子数组个数就会想到要计算以它为最小数的子数组的最大长度,自然就需要寻找它左右两边第一个比它小的数, 做过著名的Daily Temperatures那题的话很容易想到用单调栈来处理

 

提供另一种解题思路,找出数组最小值。最小值将数组一分为二。
leftLen 是左边长度,rightLen是右边长度。所有包含该最小值的子数组的最小值即该值。
个数为 (leftLen + 1)*(rightLen+1)。再分别计算左数组和右数组的子数组最小值之和。
递归求解。
如果用o(n)的算法找最小值会超时,所以我写了一个o(logn)的最小值算法。成功通过

 

   int len = arr.length;
        long ans=  0;
        int[] preSmaller = new int[len];
        int[] nextSmaller = new int[len];
        Arrays.fill(preSmaller, -1);
        Arrays.fill(nextSmaller, len);

        Deque<Integer> numStack = new ArrayDeque<>();
        for(int i=0; i<len; i++){
            while (!numStack.isEmpty() && arr[i] < arr[numStack.getLast()]){  // arr[i]比栈顶元素小,则需要出栈
                int tmpIdx = numStack.getLast();
                nextSmaller[tmpIdx] = i;
                numStack.removeLast();
            }
            numStack.addLast(i);
        }
        numStack.clear();
        for(int i=len-1; i>=0; i--){
            while (!numStack.isEmpty() && arr[i]<=arr[numStack.getLast()]){
                   int tmpIdx = numStack.getLast();
                   preSmaller[tmpIdx] = i;
                   numStack.removeLast();
            }
            numStack.addLast(i);
        }
        for(int i=0; i<len; i++){
            int width = (nextSmaller[i]-i)*(i-preSmaller[i]);
            ans += (long) width * arr[i];
        }
        int mod = (int) 1e9 + 7;
        ans = (int) (ans % mod);
        return (int)ans;

 

posted @ 2021-10-13 14:28  CharonKK  阅读(38)  评论(0)    收藏  举报