~/problems / Bit manipulation

Cover an IP range with CIDR blocks

medium ~25 min

An IPv4 address is a 32-bit number written as four bytes, like "10.0.3.7". A CIDR block "a.b.c.d/k" means every address whose first k bits match a.b.c.d; it contains 2^(32-k) addresses. We only use aligned blocks: the address in the string is the block's first address, so its last 32-k bits are zero.

Write ip_to_cidr(ip: str, n: int) -> list[str] that returns the fewest CIDR blocks that together cover exactly the n consecutive addresses starting at ip (no address outside the range, none missed). List them in increasing address order.

ip_to_cidr("10.0.3.6", 7)
# ["10.0.3.6/31", "10.0.3.8/30", "10.0.3.12/32"]
#   covers .6-.7,  .8-.11,       .12

ip_to_cidr("192.168.0.0", 256)   # ["192.168.0.0/24"]
ip_to_cidr("1.2.3.4", 1)         # ["1.2.3.4/32"]

Constraints: 1 ≤ n ≤ 1000, and the range never runs past 255.255.255.255.

Show hint

work with the address as an integer x and always take the largest aligned block that starts at x and doesn't overshoot the range. How aligned x is shows in its lowest set bit.

Topic: Bit manipulation (IP / CIDR). IPv4 as a 32-bit int; lowest set bit for block sizes.

Read the visual guide
0:00
Ctrl ' run · Ctrl ↵ submit
esc