题目:
给你一个数组 nums ,请你完成两类查询。
- 其中一类查询要求 更新 数组
nums下标对应的值 - 另一类查询要求返回数组
nums中索引left和索引right之间( 包含 )的nums元素的 和 ,其中left <= right
实现 NumArray 类:
NumArray(int[] nums)用整数数组nums初始化对象void update(int index, int val)将nums[index]的值 更新 为valint sumRange(int left, int right)返回数组nums中索引left和索引right之间( 包含 )的nums元素的 和 (即,nums[left] + nums[left + 1], ..., nums[right])
解法:
方法一:数状数组 特性参考:www.cnblogs.com/CNLayton/p/… 每个i的父节点:i+lowbit(i),每个父节点j的子节点:j-lowbit(j)。
树状数组BIT,每个节点保存了区间[i - lowbit(i) + 1, i ] 的区间前缀和。
主要操作:
- Add(index, val),对某个位置增加val。
- Get(index) 查询某个位置为结尾(包括)的前缀和。
初始化BIT时,对每个位置进行Add(index, nums[index]),时间复杂度nlog(n)
type NumArray struct {
Sums []int
Nums []int
}
// 取x的最后一位
func LowBit(x int) int {
return x & -x
}
func Constructor(nums []int) NumArray {
na := NumArray{
Sums: make([]int, len(nums) + 1), // 从index=1开始使用
Nums: nums,
}
for i := range nums {
na.Add(i + 1, nums[i])
}
return na
}
// index位置增加一个值
func (this *NumArray) Add(index int, val int) {
for i := index; i < len(this.Sums); i = i + LowBit(i) {
this.Sums[i] = this.Sums[i] + val
}
}
func (this *NumArray) Update(index int, val int) {
// NumArray保存Nums,是为了计算Update(index, val)计算增量,作为Add的第二个参数
this.Add(index + 1, val - this.Nums[index])
this.Nums[index] = val
}
func (this *NumArray) PrefixSum(index int) int {
sum := 0
for ; index > 0; index = index - LowBit(index) {
sum = sum + this.Sums[index]
}
return sum
}
func (this *NumArray) SumRange(left int, right int) int {
return this.PrefixSum(right + 1) - this.PrefixSum(left)
}
方法二:bucket思想,和数组前缀和(update O(n),SumRange O(1))相比来减少时间复杂度(达到update O(n/size),SumRange O(1))
分为size个bucket,每个bucket内的数组和保存在bockets中,更新nums[i]时,更新buckets
import "math"
type NumArray struct {
Buckets []int
Nums []int
Size int
}
// 取x的最后一位
func LowBit(x int) int {
return x & -x
}
//
func Constructor(nums []int) NumArray {
size := int(math.Sqrt(float64(len(nums))))
na := NumArray{
Buckets: make([]int, len(nums) / size + 1),
Nums: nums,
Size: size,
}
for i := range nums {
na.Buckets[i / size] = na.Buckets[i / size] + nums[i]
}
return na
}
func (this *NumArray) Update(index int, val int) {
this.Buckets[index / this.Size] = this.Buckets[index / this.Size] + val - this.Nums[index]
this.Nums[index] = val
}
func (this *NumArray) SumRange(left int, right int) int {
b1, b2 := left / this.Size, right / this.Size
ans := 0
if b1 == b2 {
for left <= right {
ans = ans + this.Nums[left]
left ++
}
return ans
}
for l1 := left; b1 == l1 / this.Size; l1 ++ {
ans = ans + this.Nums[l1]
}
for b1 := b1 + 1; b1 < b2; b1 ++ {
ans = ans + this.Buckets[b1]
}
for l2 := right; b2 == l2 / this.Size; l2 -- {
ans = ans + this.Nums[l2]
}
return ans
}