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.
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].
1. L, R and A[i] will be an integer in the range [0, 10^9].
2. The length of A will be in the range of [1, 50000].
class Solution {
public:
int numSubarrayBoundedMax(vector<int>& A, int L, int R) {
int len = A.size();
int ans = 0;
int left = -1;//左界
int right = -1;//最近合法位置
for(int i=0; iif(A[i] > R) {
left = i;
right = i;
}
else if(A[i]else {
ans += (i-left);
right = i;
}
}
return ans;
}
};
可以参考:
这一道题我一直被干扰了,被测试用例干扰了。其实可以很简单的思考这个问题。没有必要考虑数组中有哪几个数属于L到R之间。只需要关注数组中在L~R范围之外的元素。
首先,就是大于R的元素,因为任何子数组只要包含了这些元素,那么,该子数组得的最大元素一定超过了R,就不满足题目要求。所以,大于R的元素不能包含在子数组中。
然后就是小于L的元素,小于L的元素可以被包含,但是不能成为子数组的最大元素。
最好,要考虑到题目问的是连续子数组。为了方便思考,我们可以先不考虑L,因为L的情况比较复杂,单独考虑R的情况,那么一个数组中所有大于R的元素将原数组分为若干段,那么段与段之间的元素组成的任何连续子数组都满足题目要求,在我们先不考虑L 的情况下。
那么如何计算呢?某一段下标范围是:i~j,那么对于新(将要访问)的元素a,下标为x。新增加的子数组的数量应该就是:
x-i。
例如:a1, a2, a3,这时新加a4。新增加的子数组为:a4, a3a4, a2a3a4, a1a2a3a4。就是自身为1,再加上之前元素的个数。
但是这里“之前”的元素,就是段与段的划分线。用left表示。那么就有:
if(A[i] > R) {
left = i;
right = i;
}
else if(A[i]<=R && A[i]>=L){
ans += (i-left);
}
第一部分其实是段分界的更新。第二段就是刚才叙述的计算实现了。
但是我们之前没有考虑L的情况,现在考虑L的情况,根据之前所说,小于L 的元素不能成为新的子数组的最大元素。假如说现在有一个小于L 的元素出现,就比如说之前的例子中的a4,a4 < L,后面的情况暂时不管哈,那么根据之前ans的叠加方式,a4就不能单独作为子数组计算。所以这时加了4个之后还要减去一个。这时又来一个a5也小于L呢?那么a4,a5, a4a5都不能作为单独子数组。所以,这里额外要减去的子数组的数量其实就是当前元素下标到之前最近的一个满足L~R范围的元素下标之间的子数组数量,具体计算方式就是:
i-right;
这里的right就是最近的一个满足L~R范围的元素下表。所以现在不光要考虑小于L的元素的情况,还要引入right,并对right进行更新。整理就是解法一了。
这道题还是很有意思的。主要是我一开始就被误导思路了。其实想一想就能知道,根据Note的提示,不可能遍历L~R的。