关于left恰好在一个block左端而right恰好在一个block右端的情况

来源:2-3 实现 SQRT 分解的区间查询

Wonwayshon

2021-06-04 10:59:48

http://img.mukewang.com/climg/60b9948d09c215e015840680.jpg

​如果出现如图这种情况,计算时扫描一遍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回答

liuyubobobo

2021-06-05

可以,但依然是,这一方面属于常数级优化,没有改变复杂度。另一方面,这个优化只是在针对特例优化。


只有在有大量的查询 left 在一个 block 的左端或者 right 在一个 block 的右端的时候有意义。如果所有的查询这种情况很少,而每次查询都要对查询的 l 和 r 是不是 block 的边界做判断,可能反而拉低性能。


继续加油!:)

0

算法与数据结构

波波老师5年集大成之作,算法与数据结构系统学习,考试、面试、竞赛通用

2636 学习 · 1090 问题

查看课程

相似问题