Python - Non-overlapping Random Ranges

Generating non-overlapping random ranges is useful in data analysis, sampling, and testing scenarios. Python's random module provides tools to create ranges that don't intersect with each other.

Understanding the Problem

Given a start value, end value, and number of ranges needed, we generate random ranges that don't overlap. For example, with start=1, end=50, and 3 ranges, we might get [(5, 8), (15, 22), (35, 40)].

Method 1: Simple Range Generation

This approach generates random ranges but doesn't guarantee they won't overlap ?

import random

def simple_ranges(start, end, num_ranges):
    ranges = []
    for _ in range(num_ranges):
        range_start = random.randint(start, end - 1)
        range_end = random.randint(range_start, end)
        ranges.append((range_start, range_end))
    return ranges

# Example usage
result = simple_ranges(10, 100, 4)
print("Simple ranges:", result)
Simple ranges: [(23, 67), (45, 89), (12, 34), (78, 95)]

Method 2: True Non-Overlapping Ranges

This method ensures ranges never overlap by checking for conflicts ?

import random

def non_overlapping_ranges(start, end, num_ranges, min_gap=1):
    ranges = []
    max_attempts = 100
    
    for _ in range(num_ranges):
        attempts = 0
        while attempts < max_attempts:
            range_start = random.randint(start, end - min_gap)
            range_end = random.randint(range_start + min_gap, end)
            
            # Check if this range overlaps with existing ranges
            overlap = False
            for existing_start, existing_end in ranges:
                if (range_start <= existing_end and range_end >= existing_start):
                    overlap = True
                    break
            
            if not overlap:
                ranges.append((range_start, range_end))
                break
            attempts += 1
    
    return ranges

# Example usage
result = non_overlapping_ranges(1, 50, 3)
print("Non-overlapping ranges:", result)
print("Number of ranges generated:", len(result))
Non-overlapping ranges: [(8, 15), (25, 32), (40, 47)]
Number of ranges generated: 3

Method 3: Partitioned Approach

Divide the total range into segments to guarantee non-overlapping results ?

import random

def partitioned_ranges(start, end, num_ranges):
    if num_ranges <= 0:
        return []
    
    total_span = end - start
    segment_size = total_span // num_ranges
    ranges = []
    
    for i in range(num_ranges):
        segment_start = start + (i * segment_size)
        segment_end = start + ((i + 1) * segment_size) - 1
        
        if i == num_ranges - 1:  # Last segment gets remainder
            segment_end = end
        
        # Generate random range within this segment
        range_start = random.randint(segment_start, segment_end - 1)
        range_end = random.randint(range_start, segment_end)
        ranges.append((range_start, range_end))
    
    return ranges

# Example usage
result = partitioned_ranges(1, 100, 4)
print("Partitioned ranges:", result)
Partitioned ranges: [(3, 24), (28, 49), (52, 74), (78, 100)]

Comparison

Method Guarantees Non-Overlap Time Complexity Best For
Simple No O(n) Quick generation
Overlap Check Yes O(n²) Flexible ranges
Partitioned Yes O(n) Large datasets

Conclusion

Use the partitioned approach for guaranteed non-overlapping ranges with O(n) performance. The overlap-checking method provides more flexibility but has higher time complexity for large datasets.

Updated on: 2026-03-27T15:35:08+05:30

250 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements