Count Subarrays With Fixed Bounds
Count Subarrays With Fixed Bounds
You are given an integer array nums and two integers minK and maxK .
A fixed-bound subarray of nums is a subarray that satisfies the following conditions:
- The minimum value in the subarray is equal to minK .
- The maximum value in the subarray is equal to maxK .
Return the number of fixed-bound subarrays.
A subarray is a contiguous part of an array.
Example 1:
Input: nums = [1,3,5,2,7,5], minK = 1, maxK = 5 Output: 2 Explanation: The fixed-bound subarrays are [1,3,5] and [1,3,5,2].
Example 2:
Input: nums = [1,1,1,1], minK = 1, maxK = 1 Output: 10 Explanation: Every subarray of nums is a fixed-bound subarray. There are 10 possible subarrays.
Constraints:
解题思路
先说说比赛时的做法。先考虑暴力的做法,枚举右端点,从往左找到第一个小于或大于的数,假设这个数的下标为,那么很明显我们要求的子数组必定在内。然后再从往左求后缀最小值和后缀最大值,如果发现枚举到下标时有第一次同时满足后缀最小值等于和后缀最大值等于,那么此时在区间内的下标都可以作为子数组的左端点,因此以为右端点的满足条件的子数组有个。这种做法的时间复杂度是。
接下来看看能不能对枚举的过程进行优化。首先是从右往左找到第一个超出和范围内的数,这个可以开个变量来记录上一个不满足条件的数的下标,这样就不用每次都重新枚举。然后是找后缀最大值最小值,本质就是找到左边值为和的最大下标,这两个下标的最小值就是上面所说的,因此在往后枚举的过程中可以开两个变量来分别记录和的最大下标,这样就不用每次往左重新枚举了。时间复杂度就变成。
AC代码如下:
1 class Solution { 2 public: 3 long long countSubarrays(vector<int>& nums, int minK, int maxK) { 4 long long ret = 0; 5 for (int i = 0, t = -1, a = -1, b = -1; i < nums.size(); i++) { 6 if (nums[i] < minK || nums[i] > maxK) { 7 t = i; 8 a = b = -1; 9 } 10 else { 11 if (nums[i] == minK) a = i; 12 if (nums[i] == maxK) b = i; 13 if (a != -1 && b != -1) ret += min(a, b) - t; 14 } 15 } 16 return ret; 17 } 18 };
下面说一下双指针的做法,当时写的时候没想到双指针怎么做。
一样先把不在和范围内的数找出来,这样就可以把数组分成若干段,答案也不可能跨过分界点,不然就不满足数组中最小值为和最大值为,因此分别看每一段就可以了。
枚举右端点,在的左边找到一个,可以发现离越远,范围就会越大,即更有可能包含更多的和。因此可以定义为最靠近的位置,使得区间内至少包含一个和,这样到分界点这些位置与右端点都是可以构成满足要求的子数组,而到这些位置都是不可以构成满足要求的子数组。
当往右走时也只会往右走而不会往左走,因此可以用双指针。这是因为如果往右走到,对应的是在的左边(即往左走),那么由于区间内至少存在一个和,因此区间内也必定至少存在一个和,这样也是满足条件且比更靠近,这就证明指针不会往左走。
AC代码如下:
1 class Solution { 2 public: 3 long long countSubarrays(vector<int>& nums, int minK, int maxK) { 4 long long ret = 0; 5 int smin = 0, smax = 0; 6 for (int i = 0, j = 0, last = 0; i < nums.size(); i++) { 7 if (nums[i] < minK || nums[i] > maxK) { 8 last = j = i + 1; 9 smin = smax = 0; 10 } 11 else { 12 if (nums[i] == minK) smin++; 13 if (nums[i] == maxK) smax++; 14 while (j < i) { 15 if (nums[j] == minK) smin--; 16 if (nums[j] == maxK) smax--; 17 if (!smin || !smax) { 18 if (nums[j] == minK) smin++; 19 if (nums[j] == maxK) smax++; 20 break; 21 } 22 j++; 23 } 24 if (smin && smax) ret += j - last + 1; 25 } 26 } 27 return ret; 28 } 29 };
参考资料
力扣第315场周赛:https://www.bilibili.com/video/BV1Yg411a7NM/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16796515.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效