2021-09-02:IP 到 CIDR。给定起始IP和整数n,返回长度最小的CIDR块。力扣751。比如:ip=255.0.0.7,n=10,输出:["255.0.0.7/32","255.0.0.8/29","255.0.0.16/32"]。

福大大 答案2021-09-02:

具体见代码。

代码用golang编写。代码如下:

package main

import (
    "fmt"
    "strconv"
    "strings"
)

func main() {
    ip := "255.0.0.7"
    n := 10
    ret := ipToCIDR(ip, n)
    fmt.Println(ret)
}

func ipToCIDR(ip string, n int) []string {
    // ip -> 32位整数
    cur := status(ip)
    // cur这个状态,最右侧的1,能表示下2的几次方
    maxPower := 0
    // 已经解决了多少ip了
    solved := 0
    // 临时变量
    power := 0
    ans := make([]string, 0)
    for n > 0 {
        // cur最右侧的1,能搞定2的几次方个ip
        // cur : 000...000 01001000
        // 3
        maxPower = mostRightPower(cur)
        // cur : 0000....0000 00001000 -> 2的3次方的问题
        // sol : 0000....0000 00000001 -> 1 2的0次方
        // sol : 0000....0000 00000010 -> 2 2的1次方
        // sol : 0000....0000 00000100 -> 4 2的2次方
        // sol : 0000....0000 00001000 -> 8 2的3次方
        solved = 1
        power = 0
        // 怕溢出
        // solved
        for (solved<<1) <= n && (power+1) <= maxPower {
            solved <<= 1
            power++
        }
        ans = append(ans, content(cur, power))
        n -= solved
        cur += solved
    }
    return ans
}

// ip -> int(32位状态)
func status(ip string) int {
    ans := 0
    move := 24
    for _, str := range strings.Split(ip, ".") {
        // 17.23.16.5 "17" "23" "16" "5"
        // "17" -> 17 << 24
        // "23" -> 23 << 16
        // "16" -> 16 << 8
        // "5" -> 5 << 0
        strInt, err := strconv.Atoi(str)
        if err != nil {
            fmt.Println("错误", err)
            return 0
        }
        ans |= strInt << move
        move -= 8
    }
    return ans
}

var map0 = make(map[int]int)

// 1 000000....000000 -> 2的32次方

func mostRightPower(num int) int {
    // map只会生成1次,以后直接用
    if len(map0) == 0 {
        map0[0] = 32
        for i := 0; i < 32; i++ {
            // 00...0000 00000001 2的0次方
            // 00...0000 00000010 2的1次方
            // 00...0000 00000100 2的2次方
            // 00...0000 00001000 2的3次方
            map0[1<<i] = i
        }
    }
    // num & (-num) -> num & (~num+1) -> 提取出最右侧的1
    return map0[num&(-num)]
}

func content(status int, power int) string {
    builder := make([]byte, 0)
    for move := 24; move >= 0; move -= 8 {
        builder = append(builder, []byte(fmt.Sprintf("%d.", status&(255<<move)>>move))...)

    }
    builder[len(builder)-1] = '/'
    builder = append(builder, []byte(fmt.Sprintf("%d", 32-power))...)
    return string(builder)
}

执行结果如下:
在这里插入图片描述


左神java代码