题目:
给定一个整数数组 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 函数的调用次数是均匀分布的。
简单介绍:
题目:区域和检索 - 数组可修改
题目难度:中等
使用语言:JAVA
这道题来自leetcode题库的线段树标签。
概念引入:
为了方便读者理解,笔者在这里引入线段树的概念。
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
性质:除叶子结点外,其他点的值等于其左、右子树的和。(重要)
如上图,就是一个线段树。
根结点的值等于其左、右子树的和。
解题思路:
首先看题、分析题意,我们可以明确1个关键点:
1.该题是否有优于暴力解的解法?因为该题使用暴力解非常简单,但时间复杂度较高。
既然,我们已经分析出来题目的关键任务了,下面我们就可以开始思考实现了。
我们采用算法与数据结构的思路来剖析一下这题
数据结构:
要实现对数据的操作,我们要先明确存储数据的数据结构。
该题的数据结构的作用:
1.整型数组保存线段树。
2.整型保存数组的长度。
算法:
既然明确了我们的数据结构,我们就可以开始我们的算法分析了。
1.第一步,初始化工作,构建线段树。
2.第二步,更新某点的值,上方结点的值也相应更新
3.第三步,区间求和,如果左边界是左节点,就往上找,否则往右找。右边界同理
代码部分:
public class NumArray {
int [] tree;
int n;
public NumArray(int[] nums) {
n=nums.length;
tree=new int[n*2];//线段树
buildTree(nums);
}
void buildTree(int[] nums){
//叶子结点赋值
for(int i=n,j=0;i<2*n;i++,j++){
tree[i]=nums[j];
}
//线段树构造
for(int i=n-1;i>=0;i--){
tree[i]=tree[2*i]+tree[2*i+1];
}
}
public void update(int i, int val) {
i=i+n;
tree[i]=val;
//如果不是左节点就调整为左结点,如果不是右结点就调整为右结点
while(i>0){
int left=i;
int right=i;
if(left%2==1){
left--;
}
if(right%2==0){
right++;
}
tree[i/2]=tree[left]+tree[right];//利用性质更新
i=i/2;
}
}
//如果左边界是左节点,就往上找,否则往右找。右边界同理
public int sumRange(int i, int j) {
i=i+n;
j=j+n;
int sum=0;
while(i<=j){
//左边界不是左节点,往右找
if(i%2==1){
sum+=tree[i];
i++;
}
//右边界不是右节点,往左找
if(j%2==0){
sum+=tree[j];
j--;
}
i=i/2;
j=j/2;
}
return sum;
}
}
时间、空间复杂度:
结语:
晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!