最近学习到新东西,有点意思
线段树
树状数组
范围内改单点求区间和
307 区域和检索
- 树状数组
var n int
var tree []int
func lowBit(x int)int{
return x&(-x)
}
//更新向上
func update(pos int, val int){
pos++
for pos<=n{
tree[pos]+=val
pos+=lowBit(pos)
}
}
func query(pos int)int{
res:=0
for pos>0{
res+=tree[pos]
pos-=lowBit(pos)
}
return res
}
type NumArray struct {
arr []int
}
func Constructor(nums []int) NumArray {
var num NumArray
n = len(nums) //从1开始
tree = make([]int,n+1)
for i:=0;i<len(nums);i++{
update(i,nums[i])
}
num.arr = make([]int,n)
copy(num.arr,nums)
return num
}
func (this *NumArray) Update(index int, val int) {
update(index,val-this.arr[index])
this.arr[index] = val
}
func (this *NumArray) SumRange(left int, right int) int {
return query(right+1)-query(left) //整体加1
}
线段树
范围内数据求和或者最大值(O(logn)更新和查询)
有点和树状数组类似
- 包含延迟标记
package main
import (
"fmt"
)
//区间修改,区间查询,延迟标记
type Tree struct {
l,r int //左右索引
sum int //区间和
add int //延迟标记
}
var t []Tree //线段树变量
var nums []int //具体数组的值,由此数组构成线段树
//构建线段树
func build(p,l,r int){ //l r 为数组左右边界下标,从1开始
t[p].l,t[p].r= l,r
if l==r{
t[p].sum = nums[l] //具体和需要数组
return
}
mid:=(l+r)/2
build(p*2,l,mid)
build(p*2+1,mid+1,r) //右边子树
t[p].sum = t[p*2].sum+t[p*2+1].sum //子树之和
}
func spread(p int){ //延迟修改标记 先更新左右节点信息,再打标记 带标记说明此层已经修改,下一层未修改
if t[p].add>0{
t[p*2].sum+=t[p].add*(t[p*2].r-t[p*2+1].l+1) //更左边子树区间和
t[p*2+1].sum +=t[p].add*(t[p*2+1].r-t[p*2+1].l+1) //更右边
t[p*2].add+=t[p].add //左边标记
t[p*2+1].add +=t[p].add
t[p].add=0 //清除标记
}
}
//区间修改,l到r 增加d,(如果修改单点,需要注意是增两者差值)
func update(p,l,r,d int){
if l<=t[p].l&&r>=t[p].r{
t[p].sum+=d*(t[p].r-t[p].l+1)
t[p].add+=d
return
}
// 执行延迟下标
spread(p)
mid:=(t[p].l+t[p].r)/2
if l<=mid{
update(p*2,l,r,d)
}
if r>mid{
update(p*2+1,l,r,d)
}
//返回上层更新区间和,是重新计算
t[p].sum = t[p*2].sum+t[p*2+1].sum
}
//区间查询
func ask(p,l,r int)int{
if l<=t[p].l&&r>=t[p].r{
return t[p].sum
}
spread(p) //执行延迟下标
mid:=(t[p].l+t[p].r)/2
val:=0
if l<=mid{
val+=ask(p*2,l,r)
}
if r>mid{
val+=ask(p*2+1,l,r)
}
return val
}
//********************************************************************** 线段树 区间查询 已通过leetcode 307测试
//更改单点值
func updatePoint(index,val int){
update(1,index+1,index+1,val-nums[index+1])
nums[index+1] = val
}
func main(){
nums = []int{0,1,2,3,4} //0位置不使用,默认从1开始
t=make([]Tree,4*len(nums)) //开四倍空间足够使用
build(1,1,4)
fmt.Println(ask(1,1,4)) //1-4区间和
updatePoint(0,2) //下标1位置数据改为2
fmt.Println(ask(1,1,4)) //1-4区间和
}
后缀数组
处理字符串所有后缀,最长公共前缀 (待更新)