Files
LeetCode-Go/leetcode/0327.Count-of-Range-Sum/327. Count of Range Sum.go
2021-04-22 18:44:06 +08:00

92 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package leetcode
import (
"sort"
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 线段树,时间复杂度 O(n log n)
func countRangeSum(nums []int, lower int, upper int) int {
if len(nums) == 0 {
return 0
}
st, prefixSum, sumMap, sumArray, res := template.SegmentCountTree{}, make([]int, len(nums)), make(map[int]int, 0), []int{}, 0
prefixSum[0], sumMap[nums[0]] = nums[0], nums[0]
for i := 1; i < len(nums); i++ {
prefixSum[i] = prefixSum[i-1] + nums[i]
sumMap[prefixSum[i]] = prefixSum[i]
}
// sumArray 是 prefixSum 去重之后的版本,利用 sumMap 去重
for _, v := range sumMap {
sumArray = append(sumArray, v)
}
// 排序是为了使得线段树中的区间 left <= right如果此处不排序线段树中的区间有很多不合法。
sort.Ints(sumArray)
// 初始化线段树,节点内的值都赋值为 0即计数为 0
st.Init(sumArray, func(i, j int) int {
return 0
})
// 倒序是为了方便寻找 jsum(ij) 规定了 j >= i所以倒序遍历i 从大到小
for i := len(nums) - 1; i >= 0; i-- {
// 插入的 prefixSum[i] 即是 j
st.UpdateCount(prefixSum[i])
if i > 0 {
res += st.Query(lower+prefixSum[i-1], upper+prefixSum[i-1])
} else {
res += st.Query(lower, upper)
}
}
return res
}
// 解法二 树状数组,时间复杂度 O(n log n)
func countRangeSum1(nums []int, lower int, upper int) int {
n := len(nums)
// 计算前缀和 preSum以及后面统计时会用到的所有数字 allNums
allNums, preSum, res := make([]int, 1, 3*n+1), make([]int, n+1), 0
for i, v := range nums {
preSum[i+1] = preSum[i] + v
allNums = append(allNums, preSum[i+1], preSum[i+1]-lower, preSum[i+1]-upper)
}
// 将 allNums 离散化
sort.Ints(allNums)
k := 1
kth := map[int]int{allNums[0]: k}
for i := 1; i <= 3*n; i++ {
if allNums[i] != allNums[i-1] {
k++
kth[allNums[i]] = k
}
}
// 遍历 preSum利用树状数组计算每个前缀和对应的合法区间数
bit := template.BinaryIndexedTree{}
bit.Init(k)
bit.Add(kth[0], 1)
for _, sum := range preSum[1:] {
left, right := kth[sum-upper], kth[sum-lower]
res += bit.Query(right) - bit.Query(left-1)
bit.Add(kth[sum], 1)
}
return res
}
// 解法三 暴力,时间复杂度 O(n^2)
func countRangeSum2(nums []int, lower int, upper int) int {
res, n := 0, len(nums)
for i := 0; i < n; i++ {
tmp := 0
for j := i; j < n; j++ {
if i == j {
tmp = nums[i]
} else {
tmp += nums[j]
}
if tmp <= upper && tmp >= lower {
res++
}
}
}
return res
}