Fenwick树状数组
基本思想:
树状数组是用来解决在数组元素动态变化的情况下,高效的计算子数组和的一种数据结构,其更新效率和计算和的效率均为O(logn),和普通的sum数组不同的是,虽然sum数组计算子数组和的效率为O(1),但是在面对数组元素动态变化的情况下,其更新效率为O(n)。Fenwick数组的更新方式如下图:
首先需要一个辅助函数lowbit,用于计算最低位所在的位置,比如二进制110,那么它返回的是二进制10,这个函数利用补码的特性x&(-x)即可实现。有了这个函数,就可以实现数组的更新与查询。我们需要两个数组vec和tree,vec用于存储原始数据,tree是树状数组。对于更新操作,记录下该位置和原始数据之差diff,然后i += lowbit(i)进行更新。对于i到j之间的子数组之和,计算0到j和0到i两部分的和相减即可,而对于0到i之和,从第i个数开始i -= lowbit(i),并将tree[i]相加即可。代码如下,即Leetcode 307答案
1 class NumArray { 2 public: 3 NumArray(vector<int> nums) { 4 vec = vector<int>(nums.size(),0); 5 tree = vector<int>(nums.size()+1); 6 for(int i = 0;i != nums.size();++i){ 7 update(i,nums[i]); 8 vec[i] = nums[i]; 9 } 10 } 11 12 void update(int i, int val) { 13 int diff = val-vec[i]; 14 vec[i] = val; 15 int index = i+1; 16 while(index < tree.size()){ 17 tree[index] += diff; 18 index += lowBit(index); 19 } 20 } 21 22 int sumRange(int i, int j) { 23 return getSum(j+1)-getSum(i); 24 } 25 private: 26 vector<int> tree; 27 vector<int> vec; 28 int lowBit(int x){ 29 return x&(-x); 30 } 31 int getSum(int x){ 32 int result = 0; 33 while(x > 0){ 34 result += tree[x]; 35 x -= lowBit(x); 36 } 37 return result; 38 } 39 };
这是一维树状数组的情况,我们拓展一下思考二维的情况,即Leetcode 308,二维应该怎么处理呢,首先我们肯定需要一个二维数组存储真实值,对于update函数,我们对横坐标和纵坐标累加lowbit(x),代码如下
1 class NumMatrix { 2 public: 3 NumMatrix(vector<vector<int>> matrix) { 4 if(matrix.size() == 0) return; 5 grid = vector<vector<int>>(matrix.size(),vector<int>(matrix[0].size(),0)); 6 tree = vector<vector<int>>(matrix.size()+1,vector<int>(matrix[0].size()+1,0)); 7 for(int i = 0;i != matrix.size();++i){ 8 for(int j = 0;j != matrix[0].size();++j){ 9 update(i,j,matrix[i][j]); 10 } 11 } 12 } 13 14 void update(int row, int col, int val) { 15 int diff = val-grid[row][col]; 16 grid[row][col] = val; 17 col += 1; 18 row += 1; 19 for(int i = row;i < tree.size();i += lowbit(i)){ 20 for(int j = col;j < tree[i].size();j += lowbit(j)){ 21 tree[i][j] += diff; 22 } 23 } 24 } 25 26 int sumRegion(int row1, int col1, int row2, int col2) { 27 return getSum(row2+1,col2+1)-getSum(row1,col2+1)-getSum(row2+1,col1)+getSum(row1,col1); 28 } 29 private: 30 int getSum(int row,int col){ 31 int result = 0; 32 for(int i = row;i > 0;i -= lowbit(i)){ 33 for(int j = col;j > 0;j -= lowbit(j)) 34 result += tree[i][j]; 35 } 36 return result; 37 } 38 int lowbit(int x){ 39 return x&(-x); 40 } 41 vector<vector<int>> grid; 42 vector<vector<int>> tree; 43 }; 44 45 /** 46 * Your NumMatrix object will be instantiated and called as such: 47 * NumMatrix obj = new NumMatrix(matrix); 48 * obj.update(row,col,val); 49 * int param_2 = obj.sumRegion(row1,col1,row2,col2); 50 */
参考资料:
https://www.youtube.com/watch?v=WbafSgetDDk&t=748s