LeetCode/区间子数组个数

给你一个整数数组 nums 和两个整数:left 及 right
找出 nums 中连续、非空且其中最大元素在范围 [left, right] 内的子数组,并返回满足条件的子数组的个数

1. 遍历区间右端点 + 同时记录满足条件的左边点位

数组中不能含有大于 right的元素,
且至少含有一个处于 [left,right]区间的元素
所以遍历时只需记录最近不满足条件的点位
和最近满足条件的点位即可,可以将其之间的元素,作为新增右端点的区间左端点

class Solution {
public:
    int numSubarrayBoundedMax(vector<int>& nums, int left, int right) {
        int res = 0, last2 = -1, last1 = -1;
        for (int i = 0; i < nums.size(); i++) { //直接遍历维护右端点
            if (nums[i] >= left && nums[i] <= right) 
                last1 = i; //更新记录满足条件的最远点1
            else if (nums[i] > right) {
                last2 = i; //更新记录不满足条件的最远点2
                last1 = -1;  //当前数为点2则不存在区间满足条件
            }
            //
            if (last1 != -1) 
                res += last1 - last2;
        }
        return res;
    }
};

2. 转化问题

所有元素小于等于right数组 - 所有元素小于left数组

class Solution {
public:
    int numSubarrayBoundedMax(vector<int>& nums, int left, int right) {
        return count(nums, right) - count(nums, left - 1);
    }

    int count(vector<int>& nums, int lower) {
        int res = 0, cur = 0; //cur记录连续满足条件的长度
        for (auto x : nums) { //以x为右端点
            cur = x <= lower ? cur + 1 : 0; //满足条件增加,否则重置
            res += cur;
        }
        return res;
    }
};

3,. 区间单调栈板子

class Solution {
public:
    int numSubarrayBoundedMax(vector<int>& arr, int l, int r) {
        int n = arr.size();
        vector<int> monoStack; //单调栈
        vector<int> left(n), right(n);//左右边界,表示以i最大值的左右边界
        for (int i = 0; i < n; i++) {//从左往右找左边更大值
            while (!monoStack.empty() && arr[i] >= arr[monoStack.back()]) {//把更大的值挤出来,相等的视为更大(即最右边值统御左边相同元素)
                monoStack.pop_back();
            }
            left[i] = i - (monoStack.empty() ? -1 : monoStack.back()); //左区间长度
            monoStack.emplace_back(i);//放入坐标
        }
        monoStack.clear();
        for (int i = n - 1; i >= 0; i--) { //从右往左找右边更大值
            while (!monoStack.empty() && arr[i] > arr[monoStack.back()]) {
                monoStack.pop_back();
            }
            right[i] = (monoStack.empty() ? n : monoStack.back()) - i; //右区间长度
            monoStack.emplace_back(i);
        }
        int ans = 0;
        for (int i = 0; i < n; i++){  //计算每个值的贡献
            if(arr[i]>r||arr[i]<l) continue;
            ans = ans + left[i] * right[i]; 
        }
        return ans;
    }
};
posted @ 2023-06-12 18:39  失控D大白兔  阅读(12)  评论(0编辑  收藏  举报