307. 区域和检索 - 数组可修改
题目描述:
给你一个数组 nums ,请你完成两类查询。
其中一类查询要求 更新 数组 nums 下标对应的值
另一类查询要求返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的 和 ,其中 left <= right
实现 NumArray 类:
NumArray(int[] nums) 用整数数组 nums 初始化对象
void update(int index, int val) 将 nums[index] 的值 更新 为 val
int sumRange(int left, int right) 返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的 和 (即,nums[left] + nums[left + 1], …, nums[right])
考察重点:可以直接以数组记录每个索引点的数组和,也可以使用线段树的数组形式进行存储。二者运行时间分别为:
数组索引
type NumArray struct {
nums []int
sum []int
}
func Constructor(nums []int) NumArray {
sum := make([]int, len(nums))
sum[0] = nums[0]
for i := 1;i < len(nums);i ++{
sum[i] = sum[i-1] + nums[i]
}
return NumArray{nums: nums, sum: sum}
}
func (this *NumArray) Update(index int, val int) {
temp := this.nums[index] - val
for i := index;i < len(this.nums);i ++{
this.sum[i] -= temp
}
this.nums[index] = val
}
func (this *NumArray) SumRange(left int, right int) int {
if left == 0{
return this.sum[right]
}
return this.sum[right] - this.sum[left-1]
}
线段树
type NumArray1 struct {
trees []int
nLen int
}
/**
偶数个:1,2,3,4
10
3 7
1 2 3 4
奇数个:1,2,3
6
1 5
2 3
可以发现叶节点比内部节点多1,所以n-(2n-1)存放叶节点,1-(n-1)存放内部节点
*/
func Constructor11(nums []int) NumArray1 {
nLen := len(nums)
trees := make([]int, 2*nLen) //构建2*n的空间来存放线段树
for i, j := nLen, 0; i < 2*nLen; i++ { //n 到 2n-1用来存放原数组(叶节点)
trees[i] = nums[j]
j++
}
for i := nLen - 1; i > 0; i-- { // n-1 到 0 用来存放左右节点和
trees[i] = trees[2*i] + trees[2*i+1]
}
return NumArray1{trees: trees, nLen: nLen}
}
func (tt *NumArray1) Update(index int, val int) {
index = index + tt.nLen //index存放在index + n位置上
tt.trees[index] = val
for index > 0 { //依次更新所有父节点的值
right, left := index, index
if index%2 == 0 { //为零说明index在左子树,right++,否则left--;left和right分别在index/2的左右两边
right = index + 1
} else {
left = index - 1
}
tt.trees[index/2] = tt.trees[right] + tt.trees[left]
index /= 2
}
}
func (tt *NumArray1) SumRange(left int, right int) int {
// get leaf with value 'l'
left += tt.nLen
// get leaf with value 'r'
right += tt.nLen
sum := 0
for left <= right {
if (left % 2) == 1 { //如果left是右子树,则只加当前left,不再由这个left向其父节点延伸
sum += tt.trees[left]
left++
}
if (right % 2) == 0 { //如果right是左子树,则只加当前right,不再由这个right向其父节点延伸
sum += tt.trees[right]
right--
}
left /= 2
right /= 2
}
return sum
}