「这是我参与2022首次更文挑战的第37天,活动详情查看:2022首次更文挑战」
看一百遍美女,美女也不一定是你的。但你刷一百遍算法,知识就是你的了~~
谁能九层台,不用累土起!
题目
给你一个整数数组 nums 以及两个整数 lower 和 upper 。求数组中,值位于范围 [lower, upper] (包含 lower 和 upper)之内的 区间和的个数 。
区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。
示例 1:
输入: nums = [-2,5,-1], lower = -2, upper = 2
输出: 3
解释: 存在三个区间:[0,0]、[2,2] 和 [0,2] ,对应的区间和分别是:-2 、-1 、2 。
示例 2:
输入: nums = [0], lower = 0, upper = 0
输出: 1
提示:
1 <= nums.length <= 105-231 <= nums[i] <= 231 - 1-105 <= lower <= upper <= 105- 题目数据保证答案是一个 32 位 的整数
解题思路
- 我们对数组进行遍历,在遍历的同时我们从遍历到的项开始向后遍历
- 如果两个遍历的索引值相同,重置区间和
- 否则对区间和进行累加
- 如果区间和在范围内,将计数
+1
解题代码
var countRangeSum = function(nums, lower, upper) {
let count= 0,sum = 0
for(let i =0;i<nums.length;i++){
for(let j=i;j<nums.length;j++){
sum = j===i?nums[j]:sum+nums[j];
if(sum >=lower&&sum<=upper){
count++
}
}
}
return count
};
很遗憾,这个解法会报超时
优化解法
既然上面的方法不行,我们换一种方法,这次我们使用归并排序。
- 先求出
nums的前缀和数组 - 在归并排序过程中进行满足条件的区间个数的统计
- 递归回溯,每次得到两个升序数组
- 固定一个数组的索引
i,找另一个数组前缀和差在区间[lower, upper]的索引 - 指针
p1向右,找前缀和差>=lower第一个索引 - 指针
p2从p1位置起向右,找前缀和差>upper第一个索引
var countRangeSum = function(nums, lower, upper) {
const sums = [0]
for(let i = 1; i <= nums.length; i++) {
sums[i] = sums[i - 1] + nums[i - 1]
}
function merge_sort(l,r,f) {
if(l>=r) return 0
let m = l+r>>>1,i = l,p1 = m+1,p2,a
let res = merge_sort(l,m) + merge_sort(m+1,r)
while(i<=m){
while(p1 <= r && sums[p1] - sums[i] < lower) {
p1++
}
p2 = p1
while(p2 <= r && sums[p2] - sums[i] <= upper) {
p2++
}
res += p2 - p1
i++
}
if (f === 1) return res
i = 0, p1 = l, p2 = m + 1, a = []
while(p1 <= m || p2 <= r) {
a[i++] = p2 > r || p1 <= m && sums[p1] < sums[p2] ? sums[p1++] : sums[p2++]
}
for(i = 0; i < a.length; i++) {
sums[l + i] = a[i]
}
return res
}
return merge_sort(0,sums.length-1,1)
};
如有任何问题或建议,欢迎评论区留言讨论!