PracHub
QuestionsPremiumLearningGuidesCheatsheetNEWCareers

Quick Overview

English summary: This question evaluates proficiency with IP addressing, bitwise operations, and iterator implementation in code, testing competencies in binary arithmetic, CIDR range calculation, and memory- and time-aware iteration.

  • medium
  • OpenAI
  • Coding & Algorithms
  • Software Engineer

Implement IPv4 iterators and CIDR expansion

Company: OpenAI

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

## Problem: IPv4 Iterators and CIDR Expansion You are implementing utilities to iterate over IPv4 addresses. An IPv4 address is in dotted-decimal form: `A.B.C.D`, where each octet is an integer in `[0, 255]`. Conceptually, an IP can be treated as an unsigned 32-bit integer: \[ (A \ll 24) + (B \ll 16) + (C \ll 8) + D \] ### Part 1 — Forward Iterator Implement a Python class `IPv4Iterator(start_ip: str)` that iterates forward from `start_ip` (inclusive) up to `255.255.255.255` (inclusive). - Must implement the Python iterator protocol: `__init__`, `__iter__`, `__next__`. - Each `__next__()` returns the next IP as a dotted string. - When the iteration is finished, raise `StopIteration`. Example: - Input: `start_ip = "192.168.0.1"` - Output sequence: `"192.168.0.1"`, `"192.168.0.2"`, ... , `"255.255.255.255"` ### Part 2 — Reverse Iterator Implement a reverse iterator `IPv4ReverseIterator(end_ip: str)` that iterates backward from `end_ip` (inclusive) down to `0.0.0.0` (inclusive). Example: - Input: `end_ip = "192.168.0.255"` - Output sequence: `"192.168.0.255"`, `"192.168.0.254"`, ... , `"0.0.0.0"` ### Part 3 — CIDR Range Expansion Given a CIDR string like `"192.168.1.0/24"`, compute the **start IP** and **end IP** of the CIDR range using bitwise operations, then iterate through and return all IPs in that range (inclusive). CIDR format: `base_ip/prefix_len` - `base_ip` is a dotted IPv4 string. - `prefix_len` is an integer `n` in `[0, 32]` meaning the first `n` bits are fixed (network bits) and the remaining `32-n` bits vary (host bits). Requirements: - Use bitwise masking to compute: - `start_ip` (network address) - `end_ip` (broadcast/highest address) - Then iterate all addresses from `start_ip` to `end_ip` inclusive. Example: - Input: `"192.168.1.0/24"` - Start: `"192.168.1.0"` - End: `"192.168.1.255"` ### Part 4 — Optimization Discussion Discuss how you would optimize time and space complexity for the above tasks, especially for large CIDR ranges (e.g., `/8` or `/0`). ### Assumptions / Clarifications - You may assume inputs are valid IPv4/CIDR strings unless you choose to add validation. - Clearly define behavior at boundaries (e.g., starting at `255.255.255.255`, ending at `0.0.0.0`).

Quick Answer: English summary: This question evaluates proficiency with IP addressing, bitwise operations, and iterator implementation in code, testing competencies in binary arithmetic, CIDR range calculation, and memory- and time-aware iteration.

Part 1: Forward IPv4 Iterator Slice

Implement the forward behavior of an IPv4 iterator. Given a starting IPv4 address and an integer n, return the first n addresses that would be produced by iterating forward from start_ip, inclusive. If the sequence reaches 255.255.255.255 before n values are produced, stop there.

Constraints

  • start_ip is a valid IPv4 address.
  • 0 <= n <= 100000
  • Do not produce any address greater than 255.255.255.255.

Examples

Input: ('192.168.0.1', 3)

Expected Output: ['192.168.0.1', '192.168.0.2', '192.168.0.3']

Explanation: A basic forward walk from a normal starting address.

Input: ('192.168.0.255', 3)

Expected Output: ['192.168.0.255', '192.168.1.0', '192.168.1.1']

Explanation: This crosses an octet boundary.

Input: ('255.255.255.255', 3)

Expected Output: ['255.255.255.255']

Explanation: Edge case: the iterator starts at the final IPv4 address.

Input: ('0.0.0.0', 0)

Expected Output: []

Explanation: Edge case: requesting zero values should return an empty list.

Solution

def solution(start_ip, n):
    def ip_to_int(ip):
        a, b, c, d = map(int, ip.split('.'))
        return (a << 24) | (b << 16) | (c << 8) | d

    def int_to_ip(value):
        return '.'.join(str((value >> shift) & 255) for shift in (24, 16, 8, 0))

    if n <= 0:
        return []

    current = ip_to_int(start_ip)
    limit = 0xFFFFFFFF
    steps = min(n, limit - current + 1)

    return [int_to_ip(current + i) for i in range(steps)]

Time complexity: O(k), where k is the number of addresses returned. Space complexity: O(k).

Hints

  1. Convert the IPv4 string into a 32-bit integer so incrementing becomes simple.
  2. The largest possible IPv4 value is 2^32 - 1.

Part 2: Reverse IPv4 Iterator Slice

Implement the reverse behavior of an IPv4 iterator. Given an ending IPv4 address and an integer n, return the first n addresses that would be produced by iterating backward from end_ip, inclusive. If the sequence reaches 0.0.0.0 before n values are produced, stop there.

Constraints

  • end_ip is a valid IPv4 address.
  • 0 <= n <= 100000
  • Do not produce any address smaller than 0.0.0.0.

Examples

Input: ('192.168.0.255', 3)

Expected Output: ['192.168.0.255', '192.168.0.254', '192.168.0.253']

Explanation: A normal reverse walk.

Input: ('10.0.0.0', 2)

Expected Output: ['10.0.0.0', '9.255.255.255']

Explanation: This crosses an octet boundary while moving backward.

Input: ('0.0.0.0', 5)

Expected Output: ['0.0.0.0']

Explanation: Edge case: the iterator starts at the minimum IPv4 address.

Input: ('1.0.0.0', 3)

Expected Output: ['1.0.0.0', '0.255.255.255', '0.255.255.254']

Explanation: This crosses the highest octet boundary.

Solution

def solution(end_ip, n):
    def ip_to_int(ip):
        a, b, c, d = map(int, ip.split('.'))
        return (a << 24) | (b << 16) | (c << 8) | d

    def int_to_ip(value):
        return '.'.join(str((value >> shift) & 255) for shift in (24, 16, 8, 0))

    if n <= 0:
        return []

    current = ip_to_int(end_ip)
    steps = min(n, current + 1)

    return [int_to_ip(current - i) for i in range(steps)]

Time complexity: O(k), where k is the number of addresses returned. Space complexity: O(k).

Hints

  1. Treat the IPv4 address as an unsigned 32-bit integer and subtract 1 at each step.
  2. The smallest possible IPv4 value is 0.

Part 3: Expand a CIDR Block

Given a CIDR string base_ip/prefix_len, compute the network start address and the highest address in the block using bitwise operations, then return every IPv4 address in that inclusive range. The base IP may not already be aligned to the network boundary.

Constraints

  • cidr is valid and has a prefix length in the range 0 to 32.
  • For this problem, the expanded range size will be at most 4096 addresses.
  • Use bitwise masking to compute the network and end addresses.

Examples

Input: '192.168.1.0/30'

Expected Output: ('192.168.1.0', '192.168.1.3', ['192.168.1.0', '192.168.1.1', '192.168.1.2', '192.168.1.3'])

Explanation: A /30 block contains 4 addresses.

Input: '172.16.5.9/29'

Expected Output: ('172.16.5.8', '172.16.5.15', ['172.16.5.8', '172.16.5.9', '172.16.5.10', '172.16.5.11', '172.16.5.12', '172.16.5.13', '172.16.5.14', '172.16.5.15'])

Explanation: The input IP is not aligned; masking moves the start to 172.16.5.8.

Input: '10.0.0.5/32'

Expected Output: ('10.0.0.5', '10.0.0.5', ['10.0.0.5'])

Explanation: Edge case: a /32 contains exactly one address.

Input: '0.0.0.0/31'

Expected Output: ('0.0.0.0', '0.0.0.1', ['0.0.0.0', '0.0.0.1'])

Explanation: Edge case: a /31 contains two addresses.

Solution

def solution(cidr):
    def ip_to_int(ip):
        a, b, c, d = map(int, ip.split('.'))
        return (a << 24) | (b << 16) | (c << 8) | d

    def int_to_ip(value):
        return '.'.join(str((value >> shift) & 255) for shift in (24, 16, 8, 0))

    ip_text, prefix_text = cidr.split('/')
    prefix = int(prefix_text)
    ip_value = ip_to_int(ip_text)

    if prefix == 0:
        mask = 0
    else:
        mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF

    start = ip_value & mask
    end = start | (0xFFFFFFFF ^ mask)
    addresses = [int_to_ip(value) for value in range(start, end + 1)]

    return int_to_ip(start), int_to_ip(end), addresses

Time complexity: O(m), where m is the number of addresses in the CIDR range. Space complexity: O(m).

Hints

  1. To get the network address, keep the first prefix_len bits and zero out the rest.
  2. To get the highest address in the CIDR block, set all host bits to 1.

Part 4: Optimized CIDR Summary Without Full Expansion

Large CIDR blocks such as /8 or /0 are too large to expand completely. Given a CIDR block and an integer k, return a compact summary without generating every address. Compute the total number of addresses, the start IP, the end IP, the first k addresses, and the last k addresses. If the block contains fewer than k addresses, both the first and last lists should contain the full block.

Constraints

  • cidr is valid and has a prefix length in the range 0 to 32.
  • 0 <= k <= 1000
  • The CIDR block may be as large as /0, so expanding the full range is not allowed.

Examples

Input: ('192.168.1.0/30', 2)

Expected Output: (4, '192.168.1.0', '192.168.1.3', ['192.168.1.0', '192.168.1.1'], ['192.168.1.2', '192.168.1.3'])

Explanation: A small block where only part of the range is sampled from each side.

Input: ('10.0.0.5/32', 3)

Expected Output: (1, '10.0.0.5', '10.0.0.5', ['10.0.0.5'], ['10.0.0.5'])

Explanation: Edge case: the block has only one address, so both samples contain the full block.

Input: ('0.0.0.0/0', 1)

Expected Output: (4294967296, '0.0.0.0', '255.255.255.255', ['0.0.0.0'], ['255.255.255.255'])

Explanation: Huge range: the answer must be produced without expanding all addresses.

Input: ('1.2.3.4/24', 0)

Expected Output: (256, '1.2.3.0', '1.2.3.255', [], [])

Explanation: Edge case: when k is zero, the sample lists are empty.

Solution

def solution(cidr, k):
    def ip_to_int(ip):
        a, b, c, d = map(int, ip.split('.'))
        return (a << 24) | (b << 16) | (c << 8) | d

    def int_to_ip(value):
        return '.'.join(str((value >> shift) & 255) for shift in (24, 16, 8, 0))

    ip_text, prefix_text = cidr.split('/')
    prefix = int(prefix_text)
    ip_value = ip_to_int(ip_text)

    if prefix == 0:
        mask = 0
    else:
        mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF

    start = ip_value & mask
    count = 1 << (32 - prefix)
    end = start + count - 1

    if k <= 0:
        first_k = []
        last_k = []
    else:
        take = min(k, count)
        first_k = [int_to_ip(start + i) for i in range(take)]
        last_start = end - take + 1
        last_k = [int_to_ip(last_start + i) for i in range(take)]

    return count, int_to_ip(start), int_to_ip(end), first_k, last_k

Time complexity: O(k). Space complexity: O(k).

Hints

  1. A CIDR block with prefix p contains 2^(32 - p) addresses.
  2. You can compute the first k and last k addresses directly from the integer start and end values.
Last updated: Apr 19, 2026

Loading coding console...

PracHub

Master your tech interviews with 7,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • Careers
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Simulate Infection Spread on a Grid - OpenAI (hard)
  • Implement Social Follow Recommendations - OpenAI (medium)
  • Build a Compose Rating Card - OpenAI (medium)
  • Convert IPv4 Ranges to CIDR Blocks - OpenAI (medium)
  • Implement Persistent KV Store Serialization - OpenAI (hard)