[LeetCode] 907. Sum of Subarray Minimums

题:https://leetcode.com/problems/sum-of-subarray-minimums/description/

题目

Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarray of A.

Since the answer may be large, return the answer modulo 10^9 + 7.

Example 1:

Input: [3,1,2,4]
Output: 17
Explanation: Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4]. 
Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1.  Sum is 17.

Note:

  1. 1 <= A.length <= 30000
  2. 1 <= A[i] <= 300001 <= A[i] <= 30000

题目大意

生成 数组的所有连续 子串,将所有子串的最小值求和。

思路

方法一 time O(n2) 超时

动态规划
状态 minArr[i][j] :子串长度为 (i+1)时,以 index = j 开头的子串的 最小值。
状态初始化:minArr[0][j] = A[j] ,子串长度为1时,子串最小值是它本身。
状态转移方程:minArr[i][j] = Math.min(minArr[i-1][j],A[j+i]); 以j开头,长度为 i+1的子串的最小值为 MIN(长度为 i子串的最小值,与 A[i+j]) 。
由于 只用到 minArr[i][j] 只用到 前一个 minArr[i-1][j],故可以 简化成一维。

结果为:
int res =0;
res += minArr[i][j];

由于 A.length 太大,超时。

class Solution {
    public int sumSubarrayMins(int[] A) {
        int[] minArr = A.clone();
        int res = 0;
        for(int i = 0 ; i < A.length;i++)
            for(int j  = 0;j+i<A.length;j++){
                minArr[j] = Math.min(minArr[j],A[i+j]);
                res += minArr[j];
                res %= 1000000007;
            }
        return res;
    }
}

方法二 计算 每个数 在结果中出现的次数

对于A[i]
设 j <= i ,且 A[j],A[j-1] ……,A[i-1] >= A[i]
设 k >= i ,且 A[i+1]……,A[k-1] ,A[k] > A[i]
(计算 j 中 使用 >= ,k中 使用 > 。是因为 A中可能有重复的数,计算子串时,我们取 子串 中最后出现的最小数 为 子串的唯一最小数)

故 A[i] 在结果计算中出现的次数为 (k-j+1+(k-i)(i-j))
k-j+1 以A[i]为边界 的 子串。
(k-i)
(i-j) 以 A[i]左边 为左边界 ,以 A[i]右边 为右边界 的 子串。

class Solution {
    public int sumSubarrayMins(int[] A) {
        int res = 0;
        for(int i = 0 ; i < A.length;i++){
            int j = i,k = i;
            while(j-1>=0 && A[j-1]>=A[i])
                j--;
            while(k+1<A.length && A[k+1]>A[i])
                k++;
            res =(res+(k-j+1+(k-i)*(i-j))*A[i])%1000000007;
        }
        return res;
    }
}

Your runtime beats 2.64 % of java submissions.

用时很长,可以在计算边界时继续优化。

class Solution {
    public int sumSubarrayMins(int[] A) {
        int res = 0;
        int[] rdp = new int[A.length];
        int[] ldp = new int[A.length];

        for(int i = A.length-1;i>=0;i--){
            rdp[i] = i+1;
            while(rdp[i]<A.length && A[rdp[i]] > A[i])
                rdp[i] = rdp[rdp[i]];
        }

        for(int i = 0;i<A.length;i++){
            ldp[i] = i-1;
            while(ldp[i]>=0 && A[ldp[i]] >= A[i])
                ldp[i] = ldp[ldp[i]];
        }
        
        for(int i = 0 ; i < A.length;i++){
            int j = ldp[i]+1,k = rdp[i]-1;
            res =(res+(k-j+1+(k-i)*(i-j))*A[i])%1000000007;
        }
        return res;
    }
}

Your runtime beats 95.92 % of java submissions.

猜你喜欢

转载自blog.csdn.net/u013383813/article/details/83339881