Range Sum Query

来源:互联网 发布:童声配音软件 编辑:程序博客网 时间:2024/04/19 11:46

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.

The update(i, val) function modifies nums by updating the element at index i to val.

Example:

Given nums = [1, 3, 5]sumRange(0, 2) -> 9update(1, 2)sumRange(0, 2) -> 8

Note:

  1. The array is only modifiable by the update function.
  2. You may assume the number of calls to update and sumRange function is distributed evenly.
思路一:因为区域内的值经常改变,朴素的直接查找范围需要O(n),会超时,因此考虑线段树

可以看看这个链接,关于线段树,写的挺好的。

https://leetcode.com/problems/range-sum-query-mutable/solution/

时空复杂度:

预处理:O(n) O(N)

查询:O(logN) O(1)

更新:O(logN) O(1)

class NumArray {      int[] segtree;    int n;    //int[] lazy;    public NumArray(int[] nums) {        n = nums.length;        segtree = new int[2*nums.length];        buildTree(nums);    }       public void buildTree(int[] nums){        //构建线段树,其父节点包含两个子节点区域的求和信息        //存储时segtree[]中 n到2n-1存储的叶子节点(nums数组),1-n-1存储的中间节点(区域信息),0位置未使用        for(int i = n,j = 0;i<2*n&&j<n;i++,j++){            segtree[i] = nums[j];        }        for(int i =n-1;i>0;i--){            segtree[i] = segtree[2*i] + segtree[2*i+1];        }           }         public void update(int i, int val) {        int pos = i+n;        segtree[pos] = val;                 while(pos>0){            int left = pos;            int right = pos;            if(pos%2==0)//因为构建树时,i = i*2 + i*2+1,所以左孩子为2*n为偶数,右孩子为2*n+1为奇数            {                right = pos+1;            }else{                left = pos -1;            }            segtree[pos/2] = segtree[left] + segtree[right];            pos = pos/2;        }    }                  public int sumRange(int i, int j) {        int left = i+n;        int right = j+n;        int result = 0;        while(left<=right){//范围未重合,等号表示父节点刚好表示左右的范围            if(left%2==1)//左边界是父节点的右孩子,那么其父节点的范围过大,所以不必将父节点累加,只需将其单独累加进结果,并缩小范围            {                result += segtree[left];                left++;            }            if(right%2==0)//右边界是父节点的左孩子,那么父节点的范围超出了查询范围,所以不考虑其父节点,单独将右边界的结果加入结果中            {                result += segtree[right];                right--;            }            left /= 2;//查询值其父节点,因为构建树时父节点包含了区域信息            right /=2;        }        return result;    }}/** * Your NumArray object will be instantiated and called as such: * NumArray obj = new NumArray(nums); * obj.update(i,val); * int param_2 = obj.sumRange(i,j); */
思路二:

(Sqrt decomposition)

就是预先划分出若干部分,提前算好和,加快速度
时空复杂度:

预处理:O(n) O(sqrt(N))

查询:O(sqrt(N)) O(1)

更新:  O(1)  O(1)

class NumArray {      //分而治之,没sqrt(n)为一块,预先统计出每一块的总和,加快速度    int[] block;    int len;    int[] num;    public NumArray(int[] nums) {        double l =Math.sqrt(nums.length);//计算每段的长度        len =(int)Math.ceil(nums.length/l);//九三一共需要的段数,需要向上取证,因为要包括所有的元素        block = new int[nums.length];        num = nums;        for(int i = 0;i<nums.length;i++){            block[i/len] += nums[i];        }    }       public void update(int i, int val) {        block[i/len] = block[i/len] + val - num[i];        num[i] = val;    }                  public int sumRange(int i, int j) {        int result = 0;        int lblock = i/len;        int rblock = j/len;        if(lblock == rblock){            for(int a = i;a<=j;a++){                result += num[a];            }            return result;        }else{            for(int a = i;a<=(lblock+1)*len-1;a++){                result += num[a];                            }            for(int a = lblock+1;a<rblock;a++){                result += block[a];                           }            for(int a = rblock*len;a<=j;a++){                result += num[a];                            }                  return result;        }            }}/** * Your NumArray object will be instantiated and called as such: * NumArray obj = new NumArray(nums); * obj.update(i,val); * int param_2 = obj.sumRange(i,j); */


原创粉丝点击