2021-12-30:分裂问题。 一个数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。 来自腾讯。

答案2021-12-31:

每次裂变都放到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
    }
}

执行结果如下:

图片


左神java代码