751. IP to CIDR

Given a start IP address ip and a number of ips we need to cover n, return a representation of the range as a list (of smallest possible length) of CIDR blocks.

A CIDR block is a string consisting of an IP, followed by a slash, and then the prefix length. For example: "123.45.67.89/20". That prefix length "20" represents the number of common prefix bits in the specified range.

Example 1:

Input: ip = "255.0.0.7", n = 10
Output: ["255.0.0.7/32","255.0.0.8/29","255.0.0.16/32"]
Explanation:
The initial ip address, when converted to binary, looks like this (spaces added for clarity):
255.0.0.7 -> 11111111 00000000 00000000 00000111
The address "255.0.0.7/32" specifies all addresses with a common prefix of 32 bits to the given address,
ie. just this one address.

The address "255.0.0.8/29" specifies all addresses with a common prefix of 29 bits to the given address:
255.0.0.8 -> 11111111 00000000 00000000 00001000
Addresses with common prefix of 29 bits are:
11111111 00000000 00000000 00001000
11111111 00000000 00000000 00001001
11111111 00000000 00000000 00001010
11111111 00000000 00000000 00001011
11111111 00000000 00000000 00001100
11111111 00000000 00000000 00001101
11111111 00000000 00000000 00001110
11111111 00000000 00000000 00001111

The address "255.0.0.16/32" specifies all addresses with a common prefix of 32 bits to the given address,
ie. just 11111111 00000000 00000000 00010000.

In total, the answer specifies the range of 10 ips starting with the address 255.0.0.7 .

There were other representations, such as:
["255.0.0.7/32","255.0.0.8/30", "255.0.0.12/30", "255.0.0.16/32"],
but our answer was the shortest possible.

Also note that a representation beginning with say, "255.0.0.7/30" would be incorrect,
because it includes addresses like 255.0.0.4 = 11111111 00000000 00000000 00000100 
that are outside the specified range.

Note:

  1. ip will be a valid IPv4 address.
  2. Every implied address ip + x (for x < n) will be a valid IPv4 address.
  3. n will be an integer in the range [1, 1000].

思路:直接对IP string操作不太方便,先转成int、float

Intuition

This problem is about performing the steps directly as written. The tricky part is managing the bit manipulations involved.

Let's ask the question: for a number n of ip addresses desired, and the starting address ip of that range, what is the CIDR block representing the most ip addresses in that range starting at ip? Evidently, this greedy approach will work, and we can keep repeating this until we are done, so let's just focus on creating one largest block.

Algorithm

We'll need to be able to convert ip addresses back and forth to integers (long). We can do this with some basic manipulations - see the code for more details.

Then, with an ip address like 255.0.0.24 converted to start, it ends in the binary 00011000. There are some cases. If n >= 8, then we should use the entire block 255.0.0.24/29. Otherwise, we can only take a number of addresses equal to the largest power of 2 less than or equal to n.

In a more general setting, we use the bit lengths of both n and start & -start (the lowest bit of start) to compute the mask which represents 2^(32 - \text{mask})2(32mask) ip addresses. Then, we adjust start and nappropriately.

In Java and C++, we should be careful to use long data types to represent the converted ip addresses, since the number could exceed 2^{31}231.

class Solution(object):
    def ipToInt(self, ip):
        ans = 0
        for x in ip.split('.'):
            ans = 256 * ans + int(x)
        return ans

    def intToIP(self, x):
        return ".".join(str((x >> i) % 256)
                        for i in (24, 16, 8, 0))

    def ipToCIDR(self, ip, n):
        start = self.ipToInt(ip)
        ans = []
        while n:
            mask = max(33 - (start & -start).bit_length(),
                       33 - n.bit_length())
            ans.append(self.intToIP(start) + '/' + str(mask))
            start += 1 << (32 - mask)
            n -= 1 << (32 - mask)
        return ans
    
s=Solution()
print(s.ipToCIDR(ip = "255.0.0.7", n = 10))


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Here's an optimized version of the code: ``` def network_planes_check(self): LOG.info('start network_planes_check...') err_msgs = [] with open(self.JSON_PATH, 'r') as f: data = json.load(f) ip_versions = set() # Use set to avoid duplicates for vxlan_plane in data["vxlan_planes"]: for info in vxlan_plane["ip_ranges"]: cidr, start, end = info.get("cidr"), info.get("start"), info.get("end") if cidr and start and end: # Check if cidr format is correct try: ip_network = ipaddress.ip_network(cidr) except ValueError: err_msgs.append("Error: cidr format is incorrect") continue ip_versions.add(ip_network.version) if (ipaddress.ip_address(start) not in ip_network or ipaddress.ip_address(end) not in ip_network): err_msgs.append('start_ip %s or end_ip %s is not in cidr %s' % (start, end, cidr)) elif ipaddress.ip_address(start) > ipaddress.ip_address(end): err_msgs.append('start_ip %s is not less than end_ip %s' % (start, end)) else: err_msgs.append('IP is valid') else: err_msgs.append("Error: cidr/start/end is not configured") if len(ip_versions) > 1: err_msgs.append("Error: cidr is mixed ipv4/ipv6") return err_msgs ``` Here are the changes I made: - Used `info.get("cidr")` instead of `info["cidr"]` to avoid a `KeyError` if `cidr` is missing. - Used `set()` to keep track of the IP versions encountered, so we can check if there's a mix of IPv4 and IPv6. - Moved the check for `cidr/start/end` outside the `try` block, since we don't need to catch a `ValueError` for that. - Simplified the checks for `start` and `end` being in the CIDR range, and for `start` being less than `end`. - Used `continue` to skip to the next iteration of the loop if the CIDR format is incorrect.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值