关于left恰好在一个block左端而right恰好在一个block右端的情况
来源:2-3 实现 SQRT 分解的区间查询
Wonwayshon
2021-06-04 10:59:48

如果出现如图这种情况,计算时扫描一遍block1和3全部元素求和似乎有些浪费,觉得应该增加上这种情况的判断好直接利用blocks数组中处理好的和,修改了sumRange函数的代码,全部代码如下
import java.util.Arrays;
class NumArrayOptimized {
private int[] data,blocks;
private int length;
private int blocksNum;
private int blockSize;
public NumArrayOptimized(int[] nums) {
length = nums.length;
if(length==0){
return;
}
data = Arrays.copyOf(nums, length);
blockSize = (int) Math.sqrt(length);
blocksNum = length / blockSize + (length % blockSize > 0 ? 1 : 0);
blocks = new int[blocksNum];
for(int i=0;i<length;i++){
blocks[i / blockSize] += data[i];
}
}
public int sumRange(int left, int right) {
if(left<0||left>=length||right<0||right>=length||left>right){
return 0;
}
int startBlock = left / blockSize;
int endBlock = right / blockSize;
int result=0;
if(startBlock==endBlock){
for(int i=left;i<=right;i++){
result += data[i];
}
return result;
}
if(left==startBlock*blockSize){
result += blocks[startBlock];
}else{
for (int i = left; i < (startBlock + 1) * blockSize; i++) {
result += data[i];
}
}
for(int j=startBlock+1;j<endBlock;j++){
result += blocks[j];
}
if(right==(endBlock+1)*blockSize-1 || right==length-1){
result += blocks[endBlock];
}else {
for (int i = endBlock * blockSize; i <= right; i++) {
result += data[i];
}
}
return result;
}
public void update(int index, int val) {
int blockIndex = index / blockSize;
blocks[blockIndex] -= data[index];
blocks[blockIndex] += val;
data[index] = val;
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(left,right);
*/
1回答
可以,但依然是,这一方面属于常数级优化,没有改变复杂度。另一方面,这个优化只是在针对特例优化。
只有在有大量的查询 left 在一个 block 的左端或者 right 在一个 block 的右端的时候有意义。如果所有的查询这种情况很少,而每次查询都要对查询的 l 和 r 是不是 block 的边界做判断,可能反而拉低性能。
继续加油!:)
相似问题