分裂问题。
一个数n,可以分裂成一个数组[n/2, n%2, n/2],
这个数组中哪个数不是1或者0,就继续分裂下去。
比如 n = 5,一开始分裂成[2, 1, 2],
[2, 1, 2]这个数组中不是1或者0的数,会继续分裂下去,比如两个2就继续分裂,
[2, 1, 2] -> [1, 0, 1, 1, 1, 0, 1],
那么我们说,5最后分裂成[1, 0, 1, 1, 1, 0, 1]。
每一个数都可以这么分裂,在最终分裂的数组中,假设下标从1开始,
给定三个数n、l、r,返回n的最终分裂数组里[l,r]范围上有几个1。
n <= 2 ^ 50,n是long类型,
r - l <= 50000,l和r是int类型。
我们的课加个码:
n是long类型随意多大都行,
l和r也是long类型随意多大都行,但要保证l<=r。
每次裂变都放到map中。
时间复杂度:O(logN)。
空间复杂度:O(logN)。
代码用golang编写。代码如下:
package main
import "fmt"
func main() {
ret := nums2(5, 4, 7)
fmt.Println(ret)
}
func nums2(n, l, r int) int {
allMap := make(map[int]int)
return dp(n, l, r, allMap)
}
func size(n int) int {
if n == 1 || n == 0 {
return 1
} else {
half := size(n / 2)
return (half << 1) + 1
}
}
func dp(n, l, r int, allMap map[int]int) int {
if n == 1 || n == 0 {
return twoSelectOne(n == 1, 1, 0)
}
half := size(n / 2)
all := (half << 1) + 1
mid := n & 1
if l == 1 && r >= all {
if _, ok := allMap[n]; ok {
return allMap[n]
} else {
count := dp(n/2, 1, half, allMap)
ans := (count << 1) + mid
allMap[n] = ans
return ans
}
} else {
mid = twoSelectOne((l > half+1 || r < half+1), 0, mid)
left := twoSelectOne(l > half, 0, dp(n/2, l, getMin(half, r), allMap))
right := twoSelectOne(r > half+1, dp(n/2, getMax(l-half-1, 1), r-half-1, allMap), 0)
return left + mid + right
}
}
func twoSelectOne(c bool, a, b int) int {
if c {
return a
} else {
return b
}
}
func getMax(a, b int) int {
if a > b {
return a
} else {
return b
}
}
func getMin(a, b int) int {
if a < b {
return a
} else {
return b
}
}
执行结果如下: