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

posted on 2019-01-02 23:04  周浩炜  阅读(1670)  评论(0编辑  收藏  举报

导航