← 返回博客列表
Atlassian

🚨 Atlassian 2026 Interview: Merge Overlapping CI Intervals — Classic Problem, Why Do People Still Fail?

2026-01-19

Manufacturing Anxiety: Breaking the Illusion

Recently, this Atlassian interview question has been trending in North American job hunting circles.

Many people's first reaction: "LeetCode 56 original problem, easy!"

But is it really that simple?

If you just recite the template, the interviewer will immediately follow up:

Our oavoservice team analyzed this question and found that while it's a classic problem, Atlassian's approach is very engineering-focused.


Question Breakdown: Demonstrating Expertise

🔍 Original Problem

Problem – Merge Overlapping CI Intervals

Atlassian runs many CI pipelines, and we want to generate reports on usage to find cost-optimization patterns.

Each CI pipeline starts at time X and ends at time Y. We are given a list of pipeline time windows: [[X₁, Y₁], [X₂, Y₂], ...]

Objective: Find the list of non-overlapping time intervals that cover all times when at least one CI pipeline is running.

In other words, merge all overlapping intervals and return the minimal set of disjoint intervals.

🎯 Example Analysis

Example:

Input:  [[2, 5], [12, 15], [4, 8]]
Output: [[2, 8], [12, 15]]

Explanation:


Deep Dive: Building Trust

🧠 Problem Essence Analysis

Core skills being tested:

Test Point Specific Content
Sorting Logic Why sort by start point?
Greedy Strategy How to determine overlap? How to merge?
Edge Case Handling Do adjacent intervals [1,2], [2,3] count as overlapping?
Engineering Thinking How to handle large data? Streaming input?

📊 Key Insight

Why sort by start point?

After sorting, for adjacent intervals [s1, e1] and [s2, e2], we always have s1 ≤ s2.

To check overlap, just verify: s2 ≤ e1

Case 1: Overlap (s2 <= e1)
[s1=====e1]
    [s2=====e2]
Merge: [s1, max(e1, e2)]

Case 2: No Overlap (s2 > e1)
[s1===e1]
           [s2===e2]
Don't merge, keep both

Solution: Core Algorithm

Standard Solution: Sort + Linear Scan

def merge_intervals(intervals):
    """
    Atlassian CI Interval Merge
    
    Args:
        intervals: List[List[int]] - interval list [[start, end], ...]
    
    Returns:
        List[List[int]] - merged non-overlapping intervals
    """
    if not intervals:
        return []
    
    # Step 1: Sort by start point ascending
    intervals.sort(key=lambda x: x[0])
    
    # Step 2: Initialize result with first interval
    result = [intervals[0][:]]  # Copy to avoid modifying original
    
    # Step 3: Linear scan and merge
    for i in range(1, len(intervals)):
        current_start, current_end = intervals[i]
        last_end = result[-1][1]
        
        if current_start <= last_end:
            # Overlap, merge: update end time
            result[-1][1] = max(last_end, current_end)
        else:
            # No overlap, add new interval
            result.append([current_start, current_end])
    
    return result

🧪 Test Cases

# Test 1: Basic case
print(merge_intervals([[2, 5], [12, 15], [4, 8]]))
# Expected: [[2, 8], [12, 15]]

# Test 2: Complete containment
print(merge_intervals([[1, 10], [2, 5], [3, 7]]))
# Expected: [[1, 10]]

# Test 3: No overlap
print(merge_intervals([[1, 2], [5, 6], [9, 10]]))
# Expected: [[1, 2], [5, 6], [9, 10]]

# Test 4: All overlapping
print(merge_intervals([[1, 4], [2, 5], [3, 6], [4, 7]]))
# Expected: [[1, 7]]

# Test 5: Adjacent boundaries (equal counts as overlap)
print(merge_intervals([[1, 2], [2, 3], [3, 4]]))
# Expected: [[1, 4]]

# Test 6: Single interval
print(merge_intervals([[1, 5]]))
# Expected: [[1, 5]]

# Test 7: Empty input
print(merge_intervals([]))
# Expected: []

# Test 8: Unsorted input
print(merge_intervals([[5, 8], [1, 3], [2, 6], [10, 12]]))
# Expected: [[1, 8], [10, 12]]

Complexity Analysis

Operation Time Complexity Notes
Sorting O(n log n) Python Timsort
Scan & Merge O(n) Linear traversal
Total O(n log n) Sorting dominates
Space Complexity Notes
O(n) Worst case: no overlaps
O(1) If modifying in-place (not recommended)

🤯 Interviewer's Followup Traps

Followup 1: What if intervals are open intervals?

Question: Do (2, 5) and (5, 8) overlap?

Answer: No! Open interval (2, 5) doesn't include endpoint 5.

def merge_open_intervals(intervals):
    """Open interval merge: (start, end) excludes endpoints"""
    if not intervals:
        return []
    
    intervals.sort(key=lambda x: x[0])
    result = [intervals[0][:]]
    
    for i in range(1, len(intervals)):
        current_start, current_end = intervals[i]
        last_end = result[-1][1]
        
        # Open interval: strictly less than for overlap
        if current_start < last_end:
            result[-1][1] = max(last_end, current_end)
        else:
            result.append([current_start, current_end])
    
    return result

Followup 2: What if data size is 10^8?

Test Point: External sorting / Distributed processing

# Pseudocode: Distributed approach
def distributed_merge(partitions):
    """
    1. Each partition sorts and merges independently
    2. Merge all partition results together
    """
    local_results = [merge_intervals(p) for p in partitions]
    all_intervals = []
    for r in local_results:
        all_intervals.extend(r)
    return merge_intervals(all_intervals)

Followup 3: What about real-time streaming data merge?

Test Point: Data structure selection

Use Balanced BST (like TreeMap) or Skip List to maintain sorted intervals.

from sortedcontainers import SortedList

class StreamingIntervalMerger:
    def __init__(self):
        self.intervals = SortedList(key=lambda x: x[0])
    
    def add_interval(self, start, end):
        """Add new interval and merge"""
        to_merge = []
        new_start, new_end = start, end
        
        for interval in self.intervals:
            if interval[1] < start:
                continue
            if interval[0] > end:
                break
            to_merge.append(interval)
            new_start = min(new_start, interval[0])
            new_end = max(new_end, interval[1])
        
        for interval in to_merge:
            self.intervals.remove(interval)
        
        self.intervals.add([new_start, new_end])
    
    def get_intervals(self):
        return list(self.intervals)

Followup 4: Return how many CIs are running at each moment?

Test Point: Sweep line algorithm / Difference array

def count_concurrent_pipelines(intervals):
    """Return CI count at each moment"""
    events = []
    for start, end in intervals:
        events.append((start, 1))   # Start event
        events.append((end, -1))    # End event
    
    events.sort(key=lambda x: (x[0], x[1]))
    
    result = []
    current_count = 0
    
    for time, delta in events:
        current_count += delta
        result.append((time, current_count))
    
    return result

🔥 Why Most People Fail

Common Mistake Correct Approach
Forgetting to sort Must sort by start before merging
Wrong boundary check s2 <= e1 for overlap (closed interval)
Forgetting to update end Use max(e1, e2) when merging
Modifying original array Better to copy in interviews
Not handling empty input Check if not intervals at start

Code Template (Ready to Use)

def merge(intervals: list[list[int]]) -> list[list[int]]:
    """
    LeetCode 56 / Atlassian CI Intervals
    Merge all overlapping intervals
    """
    if not intervals:
        return []
    
    # Sort by start point
    intervals.sort(key=lambda x: x[0])
    
    merged = [intervals[0]]
    
    for current in intervals[1:]:
        if current[0] <= merged[-1][1]:
            # Overlap, merge
            merged[-1][1] = max(merged[-1][1], current[1])
        else:
            # No overlap, add new interval
            merged.append(current)
    
    return merged

📞 oavoservice Services

Interval merging seems simple, but Atlassian tests engineering thinking and extensibility.

If you encounter similar problems in interviews, we can provide:


👉 Add WeChat Now: Coding0201

Don't let an interval merge problem ruin your Atlassian Offer.


Original content by oavoservice team. Please credit when sharing.