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) }
执行结果如下: