开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
前言
小白算法比较菜,希望能激励我每日更新,从leetcode第一题开始,2022年目标1900分,1823分了!!
11月24日每日一题
795. 区间子数组个数
给你一个整数数组 nums 和两个整数:left 及 right 。找出 nums 中连续、非空且其中最大元素在范围 [left, right] 内的子数组,并返回满足条件的子数组的个数。
生成的测试用例保证结果符合 32-bit 整数范围。
示例 1
- 输入: nums = [2,1,4,3], left = 2, right = 3
- 输出: 3
- 解释: 满足条件的三个子数组:[2], [2, 1], [3]
示例 2
- 输入: nums = [2,9,2,5,6], left = 2, right = 8
- 输出: 7
提示
1 <= nums.length <= 1050 <= nums[i] <= 1090 <= left <= right <= 109
代码
这里分享两个做法,第一个算是暴力做法吧,首先遍历一遍,把在范围内的置1,小于left的置0,大于right的置-1
因为题目要求是最大值在left到right之间就可以,所以是可以出现小于left的情况的。
然后两层while循环,找到l和r之间不含有-1的区间段,计算这区间有多少种符合条件的,这里呢我用了前缀和。而且当l到r之间没有0的时候,直接返回(len + 1) * len / 2 即可。如果不加这一步的话,有一个测试用例会超时。
最后提交是10ms
方法二,是看评论区大佬的做法,很好理解,题目要求是最大值在left到right之间 == 最大值小于等于right - 最大值小于等于(left - 1)
至于求小于X的连续子数组,就很好做了,只需要O(n)复杂度,是个经典的题性,需要记住。
//方法一
class Solution {
public int numSubarrayBoundedMax(int[] nums, int left, int right) {
for(int i = 0; i < nums.length; i++) {
if(nums[i] >= left && nums[i] <= right) {
nums[i] = 1;
} else if(nums[i] <left){
nums[i] = 0;
} else {
nums[i] = -1;
}
}
int res = 0;
int l = 0;
int r = 0;
while(r < nums.length) {
while(r < nums.length && nums[r] == -1) {
r++;
}
l = r;
while(r < nums.length && nums[r] != -1) {
r++;
}
//求l到r(不算r)之间,有多少符合要求的
res = res + fun(nums, l ,r);
}
return res;
}
private int fun(int[] nums, int l, int r) {
int[] preSum = new int[r - l + 1];
boolean flag = true;
for (int i = l; i < r; i++) {
preSum[i + 1 - l] = preSum[i-l] + nums[i];
if(nums[i] == 0) {
flag = false;
}
}
if(flag == true) {
long len = r - l;
return (int)((len + 1) * len / 2);
}
int res = 0;
for (int i = l; i < r; i++) {
for (int j = i; j < r; j++) {
if (preSum[j - l + 1] - preSum[i - l] != 0) {
res++;
}
}
}
return res;
}
}
//方法二
class Solution {
public int numSubarrayBoundedMax(int[] nums, int left, int right) {
return numSubarrayBoundedMax(nums,right) - numSubarrayBoundedMax(nums,left - 1);
}
private int numSubarrayBoundedMax(int[] nums, int left) {
int res = 0;
int temp = 0;
for (int i = 0; i < nums.length; i++) {
if(nums[i] <= left) {
temp++;
} else {
temp = 0;
}
res += temp;
}
return res;
}
}
3.结束
1823分了。希望早日1900。knight最低是 1875.65,加油!