[LeetCode] Number of Subarrays with Bounded Maximum 有界限最大值的子数组数量

题目

We are given an array A of positive integers, and two positive integers L and R (L <= R).

Return the number of (contiguous, non-empty) subarrays such that the value of the maximum array element in that subarray is at least L and at most R.

  • Example :
    Input:
    A = [2, 1, 4, 3]
    L = 2
    R = 3
    Output: 3
    Explanation: There are three subarrays that meet the requirements: [2], [2, 1], [3].
  • Note:
    L, R and A[i] will be an integer in the range [0, 10^9].
    The length of A will be in the range of [1, 50000].

#分析题目

  • 本题给了我们一个数组,又给了我们两个数字L和R,表示一个区间范围,让我们求有多少个这样的子数组,使得其最大值在[L, R]区间的范围内。
  • 求子数组的问题,第一种暴力求解就是遍历所有的子数组,然后维护一个当前的最大值,只要这个最大值在[L, R]区间的范围内,结果res自增1即可.我们可以在这基础上略作优化.首先,如果当前数字大于R了,那么其实后面就不用再遍历了,不管当前这个数字是不是最大值,它都已经大于R了,那么最大值可能会更大,所以没有必要再继续遍历下去了。同样的剪枝也要加在内层循环中加,当curMax大于R时,直接break掉内层循环即可.(参见解法一)
  • 优化到线性的时间复杂度内完成。我们来看数组[2, 1, 4, 3],当遍历到2时,只有一个子数组[2],遍历到1时,有三个子数组,[2], [1], [2,1]。当遍历到4时,有六个子数组,[2], [1], [4], [2,1], [1,4], [2,1,4]。当遍历到3时,有十个子数组。则长度为n的数组共有n(n+1)/2个子数组,刚好是等差数列的求和公式。我们使用left和right来分别标记子数组的左右边界,使得其最大值在范围[L,R]内。那么当遍历到的数字大于等于L时,right赋值为当前位置i,那么每次res加上right - left,随着right的不停自增1,每次加上的right - left,实际上也是一个等差数列.当A[i]大于R的时候,left = i,那么此时A[i]肯定也大于等于L,于是rihgt=i,那么right - left为0,增量重置为0的操作.(参见解法二)
    #解法一
  • 时间复杂度O(n2 )
  • 空间复杂度O(1)
    #代码
class Solution {
    public int numSubarrayBoundedMax(int[] A, int L, int R) {
        int res = 0, n = A.length;
        for (int i = 0; i < n; ++i) {
            if (A[i] > R) continue;
            int curMax = Integer.MIN_VALUE;
            for (int j = i; j < n; ++j) {
                curMax = Math.max(curMax, A[j]);
                if (curMax > R) break;
                if (curMax >= L) ++res;
            }
        }
        return res;
    }
}

#解法二

  • 时间复杂度O(n)
  • 空间复杂度O(1)
    #代码
class Solution {
    public int numSubarrayBoundedMax(int[] A, int L, int R) {
        int res = 0, left = -1, right = -1;
        for(int i = 0; i < A.length; i++) {
            if(A[i] >= L) {
                right = i;
            }
            if(A[i] > R) {
                left = i;
            }
            res+=right-left;
        }
        return res;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值