307. Range Sum Query - Mutable
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) -> 9 update(1, 2) sumRange(0, 2) -> 8
Note:
- The array is only modifiable by the update function.
- You may assume the number of calls to update and sumRange function is distributed evenly.
含义:给你提供一个二维数组,然后求指定下标之间的所有数的总和,已知数组中的值可以更新,并且更新和求和操作会被频繁调用
思路一:sums[i]表示从位置0到位置i的所有数总和,nums[j] - nums[i] 即为i到j的数据总和。更新的时候,只要从位置i开始更新后面的所有nums.
思路二:树状数组对于求元素值可变数组指定下标之间值之和的问题十分适合,当然也可应用在求最大值或者最小值这类的问题中。
要了解树状数组,我们先看它的存储形式:
图片来源:树状数组
我们可以看到当i为奇数时,c[i]=a[i]。当i为偶数时,我们就需要算出i的分解因子中为2的多少次方了,这个不好解释。
举个例子:
- 当i=4时,i=22∗1,所以C[4]=A[1]+A[2]+A[3]+A[4]
- 当i=6时,i=21∗3,所以C[6]=A[5]+A[6]
- 当i=8时,i=23∗1,所以C[8]=A[1]+...+A[8]
- 当i=9时,i=20∗3,所以C[6]=A[9]
C[a]=A[a] + A[a-1] + A[a-2] + ......
将a尽可能被2整除,假设他最多能被n个2整除,C[i]就等于当前位向前加n位的总和。
这个n怎么算呢,其实就是找出最后一位1对应的数字,有一个简单的公式: i&(−i)
注意,树状数组的下标从1开始。
1 class NumArray { 2 3 int[] processed; 4 int[] nums; 5 int length; 6 public NumArray(int[] nums) { 7 length = nums.length; 8 processed = new int[length+1]; 9 this.nums = nums; 10 11 //init processed 12 for(int i = 1;i<=length;i++){ 13 int sum = 0; 14 int count = 1; 15 int counter = lowBit(i); 16 17 while(count <= counter){ 18 sum += nums[i-count]; 19 count++; 20 } 21 processed[i] = sum; 22 } 23 } 24 25 public void update(int i, int val) { 26 //更新树状数组 27 int gap = val - nums[i]; 28 nums[i] = val; 29 30 int index = i+1; 31 while(index <= length){ 32 processed[index] += gap; 33 index += lowBit(index); 34 } 35 } 36 37 public int sumRange(int i, int j) { 38 return sum(j+1) - sum(i); 39 } 40 41 private int sum(int index){ 42 int sum = 0; 43 while(index > 0){ 44 sum += processed[index]; 45 index -= lowBit(index); 46 } 47 return sum; 48 } 49 private int lowBit(int index){ 50 return index & (-index); 51 } 52 } 53 54 /** 55 * Your NumArray object will be instantiated and called as such: 56 * NumArray obj = new NumArray(nums); 57 * obj.update(i,val); 58 * int param_2 = obj.sumRange(i,j); 59 */