3.动态前缀和——树状数组模板

问题LCR 170. 交易逆序对的总数 - 力扣(LeetCode)求一个数组中逆序对的个数。

分析:该问题可以用归并排序解决,但不在本次学习分享之内。

树状数组——对于前缀和的计算,当其中一个元素改变时,与之关联的所有和全部需要重新计算,On时间复杂度。因此需要一种更有效的方法进行优化。

        算法学习笔记(2) : 树状数组 - 知乎 (zhihu.com)通过阶梯状分段数组来表示部分和,具体原理可见该文章。需要额外注意的是树状数组的长度等于原数组最大元素+1,因此需要进行离散化计算:先拷贝出一个原始数组,再排序,通过二分查找标记原数组中元素在数组中大小排序情况。有由于树状数组的排好序的,因此可以方便的统计逆序对数目。

        代码中lowbit中的x&-x代表x中只保留最后一个1时的数值;update代表对数组中对应区间进行更新(+1);query代表求取数组前缀和。

func lowbit(x int) int {
    return x & -x
}

func update(bit []int, x, v int) {
    n := len(bit)
    for i := x; i < n; i += lowbit(i) {
        bit[i] += v
    }
}

func query(bit []int, x int) int {
    sum := 0
    for i := x; i > 0; i -= lowbit(i) {
        sum += bit[i]
    }
    return sum
}

func reversePairs(nums []int) int {
    n := len(nums)
    if n <= 1 {
        return 0
    }

    tmp := make([]int, n)
    copy(tmp, nums)
    sort.Ints(tmp)
    for i := 0; i < n; i++ {
        nums[i] = sort.SearchInts(tmp, nums[i]) + 1
    }

    bit := make([]int, n+1)
    res := 0
    for i := n - 1; i >= 0; i-- {
        res += query(bit, nums[i]-1)
        update(bit, nums[i], 1)
    }
    return res
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值