目录链接:
力扣编程题-解法汇总_分享+记录-CSDN博客
GitHub同步刷题项目:
https://github.com/September26/java-algorithms
原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
描述:
给你一个数组 nums
,请你完成两类查询。
- 其中一类查询要求 更新 数组
nums
下标对应的值 - 另一类查询要求返回数组
nums
中索引left
和索引right
之间( 包含 )的nums元素的 和 ,其中left <= right
实现 NumArray
类:
NumArray(int[] nums)
用整数数组nums
初始化对象void update(int index, int val)
将nums[index]
的值 更新 为val
int sumRange(int left, int right)
返回数组nums
中索引left
和索引right
之间( 包含 )的nums元素的 和 (即,nums[left] + nums[left + 1], ..., nums[right]
)
示例 1:
输入:
["NumArray", "sumRange", "update", "sumRange"]
[[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
输出:
[null, 9, null, 8]
解释:
NumArray numArray = new NumArray([1, 3, 5]);
numArray.sumRange(0, 2); // 返回 1 + 3 + 5 = 9
numArray.update(1, 2); // nums = [1,2,5]
numArray.sumRange(0, 2); // 返回 1 + 2 + 5 = 8
提示:
1 <= nums.length <= 3 * 104
-100 <= nums[i] <= 100
0 <= index < nums.length
-100 <= val <= 100
0 <= left <= right < nums.length
- 调用
update
和sumRange
方法次数不大于3 * 104
解题思路:
这题数组的长度为310^4,如果时间复杂度是O(n2),则会超时。所以这题一定不能每次都遍历。
但是我们可以发现一个规律,就是update的时候,影响的范围很小,甚至有可能都对sumRange不产生影响,所以,我们可以把影响范围缩减到最小。
我们可以把nums数组划分为k块,暂且用N1,N2,Nk表示,则left和right会出现2种情况。
left和right属于同一块:这种情况,直接求left和right的累加值即可。
left和right不属于同一块:这种情况,求left到其所属块的尾之间的和,right所属的块的头到right之间的和,以及left和right之间的块的和。三者相加,就是最终值。
代码:
class NumArray {
private int[] nums;
private int[] pieces;
private int pieceLength;
public NumArray(int[] nums) {
this.nums = nums;
pieceLength = (int) Math.ceil(Math.sqrt(nums.length));
pieces = new int[nums.length / pieceLength + 1];
for (int i = 0; i < nums.length; i++) {
pieces[i / pieceLength] = pieces[i / pieceLength] + nums[i];
}
}
public void update(int index, int val) {
pieces[index / pieceLength] += (val-nums[index]);
nums[index] = val;
}
public int sumRange(int left, int right) {
int piece1 = left / pieceLength;
int piece2 = right / pieceLength;
int sum1 = 0, sum2 = 0, sum3 = 0;
if (piece1 == piece2) {
for (int i = left; i <= right; i++) {
sum1 += nums[i];
}
} else {
for (int i = left; i < pieceLength * (piece1+1); i++) {
sum1 += nums[i];
}
for (int i = pieceLength * piece2; i <= right; i++) {
sum3 += nums[i];
}
for (int i = piece1 + 1; i < piece2; i++) {
sum2 += pieces[i];
}
}
int sum = sum1 + sum2 + sum3;
return sum;
}
}