Merge Intervals
Merge overlapping intervals — sort by start, then sweep linearly.
3 min read
intervals sorting
Problem#
Given a collection of intervals [start, end], merge all overlapping intervals and return the resulting non-overlapping list.
Examples#
[[1,3],[2,6],[8,10],[15,18]]→[[1,6],[8,10],[15,18]][[1,4],[4,5]]→[[1,5]](touching counts as overlapping)
Constraints#
1 <= intervals.length <= 10^4.
Approach#
Sort by start. Walk through; if the current interval’s start ≤ the last merged interval’s end, extend the last; else push the current.
Solution#
class Solution {public: vector<vector<int>> merge(vector<vector<int>>& intervals) { sort(intervals.begin(), intervals.end()); vector<vector<int>> ans; for (auto& it : intervals) { if (!ans.empty() && it[0] <= ans.back()[1]) { ans.back()[1] = max(ans.back()[1], it[1]); } else { ans.push_back(it); } } return ans; }};import "sort"
func merge(intervals [][]int) [][]int { sort.Slice(intervals, func(i, j int) bool { return intervals[i][0] < intervals[j][0] }) ans := [][]int{} for _, it := range intervals { if len(ans) > 0 && it[0] <= ans[len(ans)-1][1] { if it[1] > ans[len(ans)-1][1] { ans[len(ans)-1][1] = it[1] } } else { ans = append(ans, []int{it[0], it[1]}) } } return ans}from typing import List
class Solution: def merge(self, intervals: List[List[int]]) -> List[List[int]]: intervals.sort() ans: List[List[int]] = [] for it in intervals: if ans and it[0] <= ans[-1][1]: ans[-1][1] = max(ans[-1][1], it[1]) else: ans.append(it[:]) return ansfunction merge(intervals) { intervals.sort((a, b) => a[0] - b[0]); const ans = []; for (const it of intervals) { if (ans.length > 0 && it[0] <= ans[ans.length - 1][1]) { ans[ans.length - 1][1] = Math.max(ans[ans.length - 1][1], it[1]); } else { ans.push([it[0], it[1]]); } } return ans;}class Solution { public int[][] merge(int[][] intervals) { Arrays.sort(intervals, (a, b) -> a[0] - b[0]); List<int[]> ans = new ArrayList<>(); for (int[] it : intervals) { if (!ans.isEmpty() && it[0] <= ans.get(ans.size() - 1)[1]) { ans.get(ans.size() - 1)[1] = Math.max(ans.get(ans.size() - 1)[1], it[1]); } else { ans.add(new int[]{it[0], it[1]}); } } return ans.toArray(new int[0][]); }}function merge(intervals: number[][]): number[][] { intervals.sort((a, b) => a[0] - b[0]); const ans: number[][] = []; for (const it of intervals) { if (ans.length > 0 && it[0] <= ans[ans.length - 1][1]) { ans[ans.length - 1][1] = Math.max(ans[ans.length - 1][1], it[1]); } else { ans.push([it[0], it[1]]); } } return ans;}Editorial#
Sorting by start lets us decide overlap with a one-shot comparison against the last merged interval — anything else in the sorted order will start no earlier. The max(end) accounts for fully-nested intervals (current is entirely inside the previous, end shouldn’t shrink).
Complexity#
- Time: O(n log n).
- Space: O(n) for output.
Concept revision#
Related#