Problem:

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

Analysis:

  一开始想着用一个简单的数组存取并进行更新和求和就可以,实际写的时候发现不太可行,网上找了找发现了一种新的数据结构或者说一种新的方法——树状数组(Binary Index Tree ,or Fenwick Tree)。

  树状数组常用于修改某点的值、求某个区间的和。普通数组修改某点值时间复杂度是O(1),查询的时间复杂度是O(n),对于树状数组来说修改和查询的时间复杂度都是O(logn)。

  Reference——http://blog.csdn.net/int64ago/article/details/7429868

  

  树状数组是巧妙地利用了二分,先介绍两个个“工具”——lowbit(k)和“加尾”操作。

  lowbit(k)就是把k的二进制高位全部清0,只留下最低位1,如lowbit(0101)=0001,实现:lowbit(k)=k&(-k)。

  加尾操作,把一个数k加上它自己的lowbit(k),k=k+lowbit(k),如去尾(0011)=0011+lowbit(0011)=0100。

  对a数组进行“操作”实际上是对c数组进行操作,也就是说我们正真用到的是c数组,那么c和a之间有某种关系,首先我们要找到这种关系,这就要用到第一个工具lowbit(k)。c[k]=a[k]向左边求lowbit(k)个和,比如c[0110]=a[0110]向左边求lowbit(0110)个和,也就是向左求两个和,则c[0110]=a[0110]+a[0101]。由这种方法就可以确定ck是由a中哪几个元素确定,如上图。

  上面说的是如何由c找到对应的a,那么由a找到对应的c就要用到加尾操作,因为如果我们要对a中某个值进行更改,c中的值肯定也要对应更改,所以要找到a对应的所有c。如a[0011]对应的c,加尾(0011)=0011+lowbit(0011)=0100,加尾(0100)=0100+lowbit(0100)=1000,所以a[0011]对应3个c,c[0011],c[0100],c[1000]。

  由右边的图我们可以更直观地看出对应关系,如c4直接包含了c2,c3(a3),c4(a4)(直接包括的黑方块),而c2直接包含了a1,a2,那么c4就包含了a1~a4,再如c6,包含了c6(a6),c5(a5)。

  a和c的对应关系就是这样了,为了对应更加方便,通常用的时候声明数组会多给出一个空间,从下标为1开始用,下标为0的不用,下面给出的方法也是从1开始。

//对a数组中的某一值进行加操作
void add(int k,int num)
{
while(k<=n)
{
tree[k]+=num;
k+=k&-k;
}
}
//对某一值进行更改时
void change(int k,int num)
{
int n=num-tree[k];//区别于对某值进行加操作,加操作是在原有基础上更改,而如果要直接对某值更新时要借用加操作
while(k<=n) //那么下面这段while可以改成add(n,num);
{
tree[k]+=num;
k+=k&-k;
}
}
int read(int k)//求1~k的区间和
{
int sum=0;
while(k>0)
{
sum+=tree[k];
k-=k&-k; //求区间和时会反向用加尾操作,即把c对应的a全部找出来
}
return sum;
}
int sumIK(int i,int k)//i~k的区间和
{
sum(i);
sum(k+1);
return sum(k+1)-sum(i);//借用前面的求和,但是要注意,实际上应该是k-(i-1),因为从1开始,所以两边都要加上1
}

Solution:

public class NumArray {

    int[] btree;
int[] arr; public NumArray(int[] nums) {
btree = new int[nums.length+1];
arr = nums; for(int i=0; i<nums.length; i++){
add(i+1, nums[i]);
} } void add(int i,int value){ for(;i<btree.length;i+=i&(-i))
{
btree[i]+=value; }
} void update(int i, int val) {
add(i+1, val-arr[i]);
arr[i]=val;
} public int sumRange(int i, int j) {
return sumHelp(j+1)-sumHelp(i);
}
public int sumHelp(int i){
int sum=0;
for(;i>=1;i-=i&(-i))
{
sum+=btree[i]; }
// while((boolean)i)
// {
// sum+=btree[i];
// i-=i&(-i);
// }
return sum;
}
} // Your NumArray object will be instantiated and called as such:
// NumArray numArray = new NumArray(nums);
// numArray.sumRange(0, 1);
// numArray.update(1, 10);
// numArray.sumRange(1, 2);

  

Leetcode 2——Range Sum Query - Mutable(树状数组实现)的更多相关文章

  1. leetcode 307. Range Sum Query - Mutable(树状数组)

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

  2. [Leetcode Week16]Range Sum Query - Mutable

    Range Sum Query - Mutable 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/range-sum-query-mutable/de ...

  3. [LeetCode] 307. Range Sum Query - Mutable 区域和检索 - 可变

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

  4. leetcode@ [307] Range Sum Query - Mutable / 线段树模板

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

  5. [LeetCode] 307. Range Sum Query - Mutable 解题思路

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

  6. LeetCode - 307. Range Sum Query - Mutable

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

  7. LeetCode 308. Range Sum Query 2D - Mutable

    原题链接在这里:https://leetcode.com/problems/range-sum-query-2d-mutable/ 题目: Given a 2D matrix matrix, find ...

  8. 【刷题-LeetCode】307. Range Sum Query - Mutable

    Range Sum Query - Mutable Given an integer array nums, find the sum of the elements between indices ...

  9. LeetCode(307) Range Sum Query - Mutable

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

随机推荐

  1. 【Luogu1471】方差(线段树)

    [Luogu1471]方差(线段树) 题面 这种傻逼题...自己去看把.. 题解 这题太傻比了 把方差公式拆开 维护平方和和区间和 修改就把平方和的公式拆开 简直傻逼的题目 #include<i ...

  2. 【BZOJ1087】【SCOI2005】互不侵犯(状态压缩,动态规划)

    题面 这种傻逼题懒得粘贴了... 题解 傻逼题 \(f[i][j][k]\)表示当前第\(i\)列,当前放置状态为\(j\),已经放了\(k\)个 暴力判断状态合法性,暴力判断转移合法性,然后统计答案 ...

  3. C++堆栈详解

    一.预备知识-程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. ...

  4. 初探WebSocket

    初探WebSocket node websocket socket.io 我们平常开发的大部分web页面都是主动'拉'的形式,如果需要更新页面内容,则需要"刷新"一个,但Slack ...

  5. Problem : 1412 ( {A} + {B} )

    //集合中元素是不会重复的,所以完全没有必要将两个集合合并后再进行排序,交换排序的时间效率是O(n^2),将两个集合中的元素分别排序后输出即可.输出格式也非常需要 //注意的.输出一列元素赢以cout ...

  6. js实现html转pdf+html2canvas.js截图不全的问题

    最近做项目中遇到要把整个页面保存为PDF文件,网上找了一下实现的方法都是 html2canvas.js+jsPdf.js 来实现.实现的过程是 先用html2canvas.js把html页面转成图片, ...

  7. oracle 10g数据库下的 XDB组件的重新安装

    emmmm,这是一个不做死就不会的过程!!! 今天在导出数据库时,遇到了报错信息,其实开发说这个报错没关系了,但作死如楼主,一定要把这个错给解决了,然后就有了下面的作死过程. 错误关键字是:packa ...

  8. 纯js生成验证码

    实现代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"& ...

  9. centos6上yum安装drbd(内核:2.6.32.696)

    author:headsen  chen date: 2017-11-20  15:11:21 notice: 个人原创,转载请注明,否则依法追究法律责任 前期准备: 两台机器:配置主机名分别为: l ...

  10. python中干掉tornado的连接失败日志

    用了tornado真的是比较舒服,很多事都为你做好了. 但也有不令人满意的地方--对于我这个洁癖来说,自动给我的控制台打印不受我控制的信息是不能忍受的. 连接到一个新的地方,如果失败,tornado会 ...