307. 区域和检索 - 数组可修改
307. 区域和检索 - 数组可修改
给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。
update(i, val) 函数可以通过将下标为 i 的数值更新为 val,从而对数列进行修改。
示例:
Given nums = [1, 3, 5]
sumRange(0, 2) -> 9
update(1, 2)
sumRange(0, 2) -> 8
说明:
- 数组仅可以在 update 函数下进行修改。
- 你可以假设 update 函数与 sumRange 函数的调用次数是均匀分布的。
常规想法-代码
1 class NumArray { 2 public: 3 vector<int> number; 4 vector<int> sum; 5 NumArray(vector<int>& nums) { 6 if(nums.empty()) return ; 7 sum.push_back(nums[0]); 8 number.push_back(nums[0]);// number=nums;直接赋值 9 for(int i=1;i<nums.size();i++){ 10 sum.push_back(sum[i-1]+nums[i]); 11 number.push_back(nums[i]); 12 } 13 } 14 15 void update(int i, int val) { 16 17 int tmp=number[i]; 18 number[i]=val; 19 for(int j=i;j<number.size();j++){ 20 sum[j]+=val-tmp; 21 } 22 } 23 24 int sumRange(int i, int j) { 25 if(i==0) return sum[j]; 26 return sum[j]-sum[i-1]; 27 28 } 29 };
树状数组-代码
1 class BitTree{//这里面 不需要加public 2 public: 3 vector<int> arr; 4 BitTree(){} 5 BitTree(vector<int>& nums){ 6 arr.push_back(0);//从1 到 n 存储赋值,下标0 不用 大小n+1个; 7 for(int i=0;i<nums.size();i++){ 8 arr.push_back(nums[i]); 9 } 10 for(int i=1;i<arr.size();i++){ 11 int j=i+(i&-i); 12 if(j<arr.size()){//最后一个的下标 位 arr.size()-1 13 arr[j]+=arr[i];//arr[j]=arr[j]+arr[i]; 14 } 15 } 16 } 17 void update(int index,int val){//代表 在 index位置上 加上val,之后更新相应位置 18 index+=1;//下标往后移动1位,因为 数据在 1 到n 19 while(index<arr.size()){ 20 arr[index]+=val; 21 index=index+(index&-index); 22 } 23 } 24 int prefixSum(int index){//前缀和 25 index+=1; 26 int sum=0; 27 while(index>0){ 28 sum+=arr[index]; 29 index=index-(index&-index); 30 } 31 return sum; 32 } 33 }; 34 35 class NumArray { 36 public: 37 vector<int> number;//存储原来的值 38 BitTree btree;//树状数组 39 NumArray(vector<int>& nums) { 40 if(nums.empty()) return ; 41 number=nums; 42 btree=BitTree(nums); 43 } 44 45 void update(int i, int val) { 46 btree.update(i,val-number[i]);//增加的值 是 val-nums[i] 47 number[i]=val;//更新这个位置的值 48 } 49 50 int sumRange(int i, int j) { 51 //if(i==0) return btree.prefixSum(j); 52 return btree.prefixSum(j)-btree.prefixSum(i-1); 53 } 54 };
线段树-代码
1 class NumArray { 2 public: 3 struct tree{ 4 int left,right; 5 int data; 6 }; 7 vector<tree> dt; 8 vector<int> number; 9 void build_tree(int pos,int start,int end){ 10 dt[pos].left=start,dt[pos].right=end;//保存节点的区间 11 if(start==end){//叶子 12 dt[pos].data=number[start-1];//存值, start是 索引多加了1,所以 取数据的时候减去 13 return ; 14 } 15 int mid=(start+end)/2; 16 build_tree(pos<<1,start,mid);//创建左子树 17 build_tree(pos<<1|1,mid+1,end);//右子树 18 dt[pos].data=dt[pos<<1].data+dt[pos<<1|1].data;//节点和 更新 19 //pos=1 开始 , 左孩子 2*pos,右孩子 2*pos+1; 2*pos=pos<<1;2*pos+1=pos<<1|1; 20 //pos=0 开始,左孩子 2*pos+1,右孩子2*pos+2; 21 } 22 void Update_val(int pos,int index,int val){ 23 if(dt[pos].left==dt[pos].right){ 24 dt[pos].data=val;//叶子节点 25 return ; 26 } 27 int mid=(dt[pos].left+dt[pos].right)/2; 28 if(index<=mid){//在左子树上 29 Update_val(pos<<1,index,val); 30 }else{//在右子树上 31 Update_val(pos<<1|1,index,val); 32 }//更新节点和 33 dt[pos].data=dt[pos<<1].data+dt[pos<<1|1].data; 34 } 35 int query(int pos,int start,int end){ 36 //if(dt[pos].left>end||dt[pos].right<start) return 0; 37 if(dt[pos].left>=start&&dt[pos].right<=end){ 38 return dt[pos].data; 39 } 40 int mid=(dt[pos].left+dt[pos].right)/2; 41 if(start>mid) return query(pos<<1|1,start,end);//在右边 ,是右孩子 42 if(end<=mid) return query(pos<<1,start,end);//在左边是 左孩子 43 return query(pos<<1,start,end)+query(pos<<1|1,start,end);//两边都有 44 } 45 NumArray(vector<int>& nums) { 46 if(nums.size()==0) return ; 47 int len=nums.size();//获取数组的长度 48 number=nums; 49 dt=vector<tree>(4*len);//开四倍空间 // vector<tree> tmp(4*len); dt=tmp; 50 build_tree(1,1,len);//下标为 len 51 } 52 void update(int i, int val) { 53 Update_val(1,i+1,val);//更新,从 1 根节点,更新 索引i 实际,下标要+1; 54 } 55 int sumRange(int i, int j) { 56 return query(1,i+1,j+1);//查询区间的下标要加1 57 } 58 };
线段树-代码
1 class NumArray { 2 public: 3 struct tree{ 4 int left,right; 5 int data; 6 }; 7 vector<tree> dat; 8 // vector<int> number; 9 void build_tree(vector<tree>& dt,vector<int>& number,int pos,int start,int end){ 10 dt[pos].left=start,dt[pos].right=end;//保存节点的区间 11 if(start==end){//叶子 12 dt[pos].data=number[start-1];//存值, start是 索引多加了1,所以 取数据的时候减去 13 return ; 14 } 15 int mid=(start+end)/2; 16 build_tree(dt,number,pos<<1,start,mid);//创建左子树 17 build_tree(dt,number,pos<<1|1,mid+1,end);//右子树 18 dt[pos].data=dt[pos<<1].data+dt[pos<<1|1].data;//节点和 更新 19 20 } 21 void Update_val(vector<tree>& dt,int pos,int index,int val){ 22 if(dt[pos].left==dt[pos].right){ 23 dt[pos].data=val;//叶子节点 24 return ; 25 } 26 int mid=(dt[pos].left+dt[pos].right)/2; 27 if(index<=mid){//在左子树上 28 Update_val(dt,pos<<1,index,val); 29 }else{//在右子树上 30 Update_val(dt,pos<<1|1,index,val); 31 }//更新节点和 32 dt[pos].data=dt[pos<<1].data+dt[pos<<1|1].data; 33 } 34 int query(vector<tree>& dt,int pos,int start,int end){ 35 //if(dt[pos].left>end||dt[pos].right<start) return 0; 36 if(dt[pos].left>=start&&dt[pos].right<=end){ 37 return dt[pos].data; 38 } 39 int mid=(dt[pos].left+dt[pos].right)/2; 40 if(start>mid) return query(dt,pos<<1|1,start,end);//在右边 ,是右孩子 41 if(end<=mid) return query(dt,pos<<1,start,end);//在左边是 左孩子 42 return query(dt,pos<<1,start,end)+query(dt,pos<<1|1,start,end);//两边都有 43 } 44 NumArray(vector<int>& nums) { 45 if(nums.size()==0) return ; 46 int len=nums.size();//获取数组的长度 47 vector<tree> tmp(4*len);//开四倍空间 48 dat=tmp; 49 build_tree(dat,nums,1,1,len); 50 //pos=1 开始 , 左孩子 2*pos,右孩子 2*pos+1; 51 //pos=0 开始,左孩子 2*pos+1,右孩子2*pos+2; 52 } 53 54 void update(int i, int val) { 55 Update_val(dat,1,i+1,val);//更新,从 1 根节点,更新 索引i 实际,下标要+1; 56 } 57 58 int sumRange(int i, int j) { 59 return query(dat,1,i+1,j+1);//查询区间的下标要加1 60 } 61 };
秀
1 class NumArray { 2 public: 3 vector<int> t; 4 int n; // array size 5 void build() { // build the tree 6 for (int i = n - 1; i > 0; --i) t[i] = t[i<<1] + t[i<<1|1]; 7 } 8 void modify(int p, int value) { // set value at position p 9 for (t[p += n] = value; p > 1; p >>= 1) t[p>>1] = t[p] + t[p^1]; 10 } 11 int query(int l, int r) { // sum on interval [l, r) 12 int res = 0; 13 for (l += n, r += n; l <r; l >>= 1, r >>= 1) { 14 if (l&1) res += t[l++]; 15 if (r&1) res += t[--r]; 16 } 17 return res; 18 } 19 NumArray(vector<int>& nums) { 20 if(nums.size()==0) return ; 21 n=nums.size();//获取数组的长度 22 t=vector<int>(3*n); 23 for(int i=0;i<n;i++){ 24 t[i+n]=nums[i]; 25 } 26 build(); 27 } 28 void update(int i, int val) { 29 modify(i,val);//从0开始的 30 } 31 int sumRange(int i, int j) { 32 return query(i,j+1); 33 } 34 };