跳到主要内容

2444. Bounded Subarrays

Count Subarrays With Fixed Bounds

又是一个有够适合掌握滑动窗口的好题

既然要minK和maxK两路Bounded

那我们每次挪动窗口右尾的rightIdx

先检查一下是否minKnums[rightIdx]maxKminK \leq nums[rightIdx] \leq maxK

没做到的话 代表nums[rightIdx]nums[rightIdx]摔出既定范围

rightIdx做窗口右尾的合规子数组肯定不存在

于是把窗口左端leftIdx改成rightIdx + 1

同时prevMinIdxprevMaxIdx都重置到-1

因为还不知道nums[leftIdx:]nums[leftIdx:]有没有刚好是minKminKmaxKmaxK的元素

只要nums[leftIdx:rightIdx+1]nums[leftIdx: rightIdx + 1]没谁掉出界

那我们就看这扇窗口中

最近一次做到nums[i]=minKnums[i] = minK的索引ii

prevMinIdx赋予给ii

最近一次做到nums[j]=maxKnums[j] = maxK的索引jj

prevMaxIdx赋予给jj

一旦prevMinIdxprevMaxIdx都不是-1

就来到了我们窗口凑齐题目要求的瞬间

本窗口能切的子数组有三个条件要遵守:

(1). 右尾在rightIdx

(2). 左端起码要有leftIdx 且不超过右尾

(3). 左端再大也得在min(prevMinIdx, prevMaxIdx)封顶

(1)和(2)非常直观 重点在于(3)是怎么来的

如果窗口内某个索引kk符合min(prevMinIdx, prevMaxIdx) <k< k

那么nums[k:rightIdx+1]nums[k:rightIdx + 1]必然没法同时拥有minKminKmaxKmaxK

题目要我们的子数组一起抓minKminKmaxKmaxK才行

于是当前窗口内 符合条件的子数组

C=C = min(prevMinIdx, prevMaxIdx) + 1 - leftIdx这么多

CC加入最终要回传的boundedSubarraysCount

#include <vector>
using namespace std;

long long countBoundedSubarrays(vector<int>& nums, int minK, int maxK) { // LeetCode Q.2444.
long long boundedSubarraysCount = 0;

int prevMinIdx = -1, prevMaxIdx = -1;

int leftIdx = 0;
for (int rightIdx = 0; rightIdx < nums.size(); rightIdx++) {
int num = nums[rightIdx];

if (num < minK || num > maxK) { // Reset.
prevMinIdx = -1, prevMaxIdx = -1;
leftIdx = rightIdx + 1;
continue;
}

if (num == maxK)
prevMaxIdx = rightIdx;
if (num == minK)
prevMinIdx = rightIdx;

if (min(prevMinIdx, prevMaxIdx) >= 0)
boundedSubarraysCount += min(prevMinIdx, prevMaxIdx) + 1 - leftIdx;
}

return boundedSubarraysCount;
}

Sliding Window Efficiency 时间复杂度O(n)O(n) 其中nn是输入的数组长度

空间则是O(1)O(1) 仅需四根指针 和负责记录总值的boundedSubarraysCount