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 []intsum []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] - valfor 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 []intnLen int
}/**偶数个:1,2,3,4103 71 2 3 4奇数个:1,2,361 52 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] = valfor index > 0 { //依次更新所有父节点的值right, left := index, indexif 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.nLensum := 0for 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 /= 2right /= 2}return sum
}