Given a starting IP address ip
and a number of IPs we need to cover n
, return a representation of the address range in CIDR format.
A CIDR block is a string consisting of an IP address, followed by a slash, and then the number of leading bits in the address that are fixed. For example, "192.168.0.0/20"
represents all IPs with the first 20 bits being 192.168.
followed by 0.
.x
, where x
can be anything.
The IP address is represented as a 32-bit unsigned integer, so you need to convert the IP string to an integer first. You will return a list of CIDR blocks representing the requested range. You should return the most concise list possible.
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 an integer, is 4278190087. We need to cover 10 addresses starting from 4278190087. - 4278190087 is best represented as "255.0.0.7/32", because it is a single address. - 4278190088 to 4278190095 is best represented as "255.0.0.8/29", because it covers 8 addresses in a single block. - 4278190096 is best represented as "255.0.0.16/32", because it is a single address. In total, we covered 1 + 8 + 1 = 10 addresses as required.
Constraints:
ip
is a valid IPv4 address.1 <= n <= 1000
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The IP to CIDR problem is about finding the most compact way to represent a range of IP addresses. The brute force method involves systematically trying out different CIDR block sizes, starting from the smallest possible block and working our way up to larger ones, to see if we can perfectly cover the given range.
Here's how the algorithm would work step-by-step:
def ip_to_cidr(ip_address):
ip_integer = ip_to_integer(ip_address)
results = []
while ip_integer > 0:
# Start from the largest possible CIDR block
prefix_length = 32
while prefix_length > 0:
network_address = ip_integer & ((2**32 - 1) << (32 - prefix_length))
#Check if the current IP can form a valid CIDR block
if network_address == ip_integer:
results.append(integer_to_ip(network_address) + '/' + str(prefix_length))
ip_integer -= 2**(32 - prefix_length)
break
prefix_length -= 1
if prefix_length == 0:
results.append(integer_to_ip(ip_integer) + '/32')
ip_integer -= 1
return results
def ip_to_integer(ip_address):
octets = ip_address.split('.')
result = 0
for octet in octets:
result = (result << 8) + int(octet)
return result
def integer_to_ip(ip_integer):
octet_1 = (ip_integer >> 24) & 255
octet_2 = (ip_integer >> 16) & 255
octet_3 = (ip_integer >> 8) & 255
octet_4 = ip_integer & 255
return str(octet_1) + '.' + str(octet_2) + '.' + str(octet_3) + '.' + str(octet_4)
The core idea is to convert the IP address to its numerical representation and then find the largest possible CIDR block that starts at that address. We repeatedly find the largest CIDR, add it to the solution, and then move to the next address not covered by any CIDR block.
Here's how the algorithm would work step-by-step:
def ip_to_cidr(ip_address, number_of_ips):
def ip_to_int(ip):
octets = ip.split('.')
result = 0
for octet in octets:
result = (result << 8) + int(octet)
return result
def int_to_ip(ip_int):
octet1 = (ip_int >> 24) & 255
octet2 = (ip_int >> 16) & 255
octet3 = (ip_int >> 8) & 255
octet4 = ip_int & 255
return f'{octet1}.{octet2}.{octet3}.{octet4}'
start_ip_int = ip_to_int(ip_address)
cidr_blocks = []
while number_of_ips > 0:
# Find the largest possible CIDR block
max_cidr = 32
while max_cidr > 0:
network_address = start_ip_int & (~((1 << (32 - max_cidr)) - 1))
if network_address != start_ip_int:
break
number_of_ips_in_block = 1 << (32 - max_cidr)
if number_of_ips_in_block > number_of_ips:
max_cidr -= 1
break
max_cidr -= 1
max_cidr += 1
# Create the CIDR block string
cidr_blocks.append(f'{int_to_ip(start_ip_int)}/{max_cidr}')
number_of_ips_in_block = 1 << (32 - max_cidr)
number_of_ips -= number_of_ips_in_block
start_ip_int += number_of_ips_in_block
# Prevent overflow past a 32 bit integer.
if start_ip_int > 0xFFFFFFFF:
break
return cidr_blocks
Case | How to Handle |
---|---|
ip is null or empty string | Return an empty list or throw an IllegalArgumentException as invalid input. |
n is zero | Return an empty list as there are no IPs to cover. |
n is negative | Throw an IllegalArgumentException as the number of IPs must be non-negative. |
ip is not a valid IPv4 address format | Throw an IllegalArgumentException, indicating the IP address is malformed. |
Integer overflow when converting IP to integer or calculating IP + n - 1 | Use long integer representation for IP address calculations to prevent overflow. |
Resulting IP address (IP + n - 1) exceeds the maximum IPv4 address | Handle the overflow by either wrapping around to 0 or clamping the value to the maximum IPv4 address value. |
n is very large, leading to a huge number of CIDR blocks | Ensure efficient CIDR block calculation and list building to handle large 'n' without excessive memory usage. |
IP and n such that the entire IPv4 range is covered | The algorithm should correctly return a single CIDR block representing 0.0.0.0/0. |