mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 21:22:43 +00:00
feat: refactored docs structure
This commit is contained in:
1 parent
31a1fcfdbd
commit
6247915ae5
222 files changed
+6452
-729
No files matched your search
+54
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: '435. Non-overlapping Intervals'
|
||||
description: Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Dynamic Programming", slug: "dynamic-programming" }
|
||||
- { name: "Greedy", slug: "greedy" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/183"
|
||||
sidebar:
|
||||
label: 'Non-overlapping Intervals'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `intervals = [[1,2],[2,3],[3,4],[1,3]]`
|
||||
- Output: `1`
|
||||
- Explanation: `[1,3]` can be removed and the rest of the `intervals` are non-overlapping.
|
||||
|
||||
### Example 2:
|
||||
- Input: `intervals = [[1,2],[1,2],[1,2]]`
|
||||
- Output: `2`
|
||||
- Explanation: You need to remove two `[1,2]` to make the rest of the `intervals` non-overlapping.
|
||||
|
||||
### Example 3:
|
||||
- Input: `intervals = [[1,2],[2,3]]`
|
||||
- Output: `0`
|
||||
- Explanation: You don't need to remove any of the `intervals` since they're already non-overlapping.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= intervals.length <= 10^5`
|
||||
- `intervals[i].length == 2`
|
||||
- `-5 * 10^4 <= starti < endi <= 5 * 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def eraseOverlapIntervals(self, intervals: list[list[int]]) -> int:
|
||||
intervals.sort(key=lambda x: x[0])
|
||||
result = []
|
||||
|
||||
for start, end in intervals:
|
||||
# Use '<' to avoid intervals which touch
|
||||
if result and start < result[-1][1]:
|
||||
result[-1][1] = min(result[-1][1], end)
|
||||
else:
|
||||
result.append([start, end])
|
||||
|
||||
# Difference between original and result is to remove
|
||||
return len(intervals) - len(result)
|
||||
```
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: '56. Merge Intervals'
|
||||
description: Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
- { name: "Quicksort", slug: "quicksort" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/182"
|
||||
sidebar:
|
||||
label: 'Merge Intervals'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `intervals = [[1,3],[2,6],[8,10],[15,18]]`
|
||||
- Output: `[[1,6],[8,10],[15,18]]`
|
||||
- Explanation: Since `intervals [1,3]` and `[2,6]` overlap, merge them into `[1,6]`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `intervals = [[1,4],[4,5]]`
|
||||
- Output: `[[1,5]]`
|
||||
- Explanation: Intervals `[1,4]` and `[4,5]` are considered overlapping.
|
||||
|
||||
### Example 3:
|
||||
- Input: `intervals = [[4,7],[1,4]]`
|
||||
- Output: `[[1,7]]`
|
||||
- Explanation: Intervals `[1,4]` and `[4,7]` are considered overlapping.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= intervals.length <= 10^4`
|
||||
- `intervals[i].length == 2`
|
||||
- `0 <= starti <= endi <= 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def merge(self, intervals: list[list[int]]) -> list[list[int]]:
|
||||
intervals.sort(key=lambda x: x[0])
|
||||
result = []
|
||||
|
||||
for start, end in intervals:
|
||||
if result and start <= result[-1][1]:
|
||||
result[-1][1] = max(result[-1][1], end)
|
||||
else:
|
||||
result.append([start, end])
|
||||
|
||||
return result
|
||||
```
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: '57. Insert Interval'
|
||||
description: You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the i^th interval and intervals is sorted in ascending order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/181"
|
||||
sidebar:
|
||||
label: 'Insert Interval'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `intervals = [[1,3],[6,9]], newInterval = [2,5]`
|
||||
- Output: `[[1,5],[6,9]]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]`
|
||||
- Output: `[[1,2],[3,10],[12,16]]`
|
||||
- Explanation: Because the new interval `[4,8]` overlaps with [3,5],[6,7],[8,10].
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `0 <= intervals.length <= 10^4`
|
||||
- `intervals[i].length == 2`
|
||||
- `0 <= starti <= endi <= 10^5`
|
||||
- intervals is sorted by starti in ascending order.
|
||||
- `newInterval.length == 2`
|
||||
- `0 <= start <= end <= 10^5`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def insert(
|
||||
self, intervals: list[list[int]], newInterval: list[int]
|
||||
) -> list[list[int]]:
|
||||
result = []
|
||||
i, n = 0, len(intervals)
|
||||
start, end = newInterval
|
||||
|
||||
# Everything before
|
||||
while i < n and intervals[i][1] < start:
|
||||
result.append(intervals[i])
|
||||
i += 1
|
||||
|
||||
# Everything merged
|
||||
while i < n and intervals[i][0] <= end:
|
||||
start = min(start, intervals[i][0])
|
||||
end = max(end, intervals[i][1])
|
||||
i += 1
|
||||
result.append([start, end])
|
||||
|
||||
# Everything after
|
||||
result.extend(intervals[i:])
|
||||
return result
|
||||
```
|
||||
@@ -0,0 +1,174 @@
|
||||
---
|
||||
title: Intervals
|
||||
description: 'Ranges with a start and an end are sorted, and then merged, counted, or scheduled.'
|
||||
hidden: true
|
||||
---
|
||||
|
||||
An interval is a pair `[start, end]` marking a stretch on a line:
|
||||
- the minutes a meeting occupies
|
||||
- the range a task runs
|
||||
- the span a sensor was active
|
||||
|
||||
**What interval problems ask you?**
|
||||
|
||||
- Do any two collide?
|
||||
- What does the timeline look like once you merge everything that touches?
|
||||
- How many rooms do you need so no two meetings share one?
|
||||
|
||||
:::tip
|
||||
Every one of those questions reduces to a single primitive: deciding whether two intervals overlap, and if they do, how to merge them or what part they share. Once that primitive is clear, the rest of the pattern is bookkeeping.
|
||||
:::
|
||||
|
||||
## When two intervals overlap
|
||||
|
||||
It is easier to state when two intervals do not overlap. Interval `a` sits entirely before interval `b` when `a` finishes before `b` begins, that is `a.end < b.start`. By symmetry they also miss each other when `b` ends before `a` starts. If neither of those holds, the intervals overlap.
|
||||
|
||||

|
||||
|
||||
Negating `a.end < b.start` or `b.end < a.start` gives the positive test directly: two intervals overlap exactly when `a.start <= b.end` and `b.start <= a.end`. That pair of comparisons is the whole overlap check.
|
||||
|
||||
## The Merged Region
|
||||
|
||||
When two intervals overlap, you can merge them into one interval that covers both. Its start is the earlier of the two starts, and its end is the later of the two ends: `[min(a.start, b.start), max(a.end, b.end)]`. The merged interval begins as soon as either interval starts, and it ends only once both have stopped.
|
||||
|
||||

|
||||
|
||||
## The Shared Region
|
||||
|
||||
When two intervals overlap, the part they share is itself an interval. Its start is the later of the two starts, and its end is the earlier of the two ends: `[max(a.start, b.start), min(a.end, b.end)]`. The overlap begins only once both intervals have started, and it ends the moment either one stops.
|
||||
|
||||

|
||||
|
||||
:::tip
|
||||
Merge grows, overlap shrinks. Merge uses `[min, max]` and covers both intervals. Overlap uses `[max, min]` and keeps only the part both share.
|
||||
:::
|
||||
|
||||
## Sort by Start first
|
||||
|
||||
Left unsorted, checking a list of intervals means comparing every pair, which is `O(n^2)`. Sorting the intervals by start time removes that cost. Once the list is in start order, any interval can only overlap ones that come after it and begin before it ends, so a single left-to-right pass is enough to merge, count, or detect collisions.
|
||||
|
||||
Sorting by start is the standard first line of almost every interval solution, and the problems below all lean on it.
|
||||
|
||||
That gives the template every interval problem in this section builds on: sort by start, then sweep once, comparing each interval against the last one you kept.
|
||||
|
||||
|
||||
:::note[Input]
|
||||
`[[1,3], [8,10], [2,6], [4,5], [10,12]]`
|
||||
:::
|
||||
|
||||
:::note[After sort]
|
||||
`[[1,3], [2,6], [4,5], [8,10], [10,12]]`
|
||||
:::
|
||||
|
||||
```python
|
||||
# Time: O(n log n)
|
||||
# Space: O(n)
|
||||
def interval_pattern(intervals):
|
||||
# 1. Sort by start time
|
||||
intervals.sort(key=lambda x: x[0])
|
||||
result = []
|
||||
for start, end in intervals:
|
||||
# 2. Overlap with the last kept interval? start <= last end
|
||||
if result and start <= result[-1][1]:
|
||||
# Merge: extend the end of the last interval
|
||||
result[-1][1] = max(result[-1][1], end)
|
||||
else:
|
||||
# 3. No overlap: keep this interval as-is
|
||||
result.append([start, end])
|
||||
return result
|
||||
```
|
||||
|
||||
<Expandable title="Show trace table">
|
||||
|
||||
| i | `[start, end]` | `result[-1]` | `start <= result[-1][1]`? | Action | `result` after |
|
||||
|---|---|---|---|---|---|
|
||||
| 0 | `[1,3]` | — | — (empty) | append | `[[1,3]]` |
|
||||
| 1 | `[2,6]` | `[1,3]` | `2 <= 3` ✅ | end = `max(3,6)` = 6 | `[[1,6]]` |
|
||||
| 2 | `[4,5]` | `[1,6]` | `4 <= 6` ✅ | end = `max(6,5)` = 6 | `[[1,6]]` |
|
||||
| 3 | `[8,10]` | `[1,6]` | `8 <= 6` ❌ | append | `[[1,6], [8,10]]` |
|
||||
| 4 | `[10,12]` | `[8,10]` | `10 <= 10` ✅ | end = `max(10,12)` = 12 | `[[1,6], [8,12]]` |
|
||||
|
||||
|
||||
:::tip[Output]
|
||||
`[[1,6], [8,12]]`
|
||||
- **Row 2:** `[4,5]` sits inside `[1,6]`. Setting `end = 5` without `max` would cut the interval short. `max` keeps 6.
|
||||
- **Row 4:** `[8,10]` and `[10,12]` only touch at 10. The `<=` check merges them. With `<`, you would get two intervals.
|
||||
:::
|
||||
|
||||
</Expandable>
|
||||
|
||||
|
||||
## Insert into a sorted list
|
||||
|
||||
Sometimes the list is already sorted and has no overlaps, and you must add one new interval. You could append it, sort, and run the template. That works, but it pays `O(n log n)` for a sort you do not need.
|
||||
|
||||
A sorted list with no overlaps splits into three parts around the new interval, in this order:
|
||||
|
||||
1. Intervals that end **before** the new one starts. Keep them as they are.
|
||||
2. Intervals that **overlap** the new one. Merge each into it with `[min, max]`.
|
||||
3. Intervals that start **after** the new one ends. Keep them as they are.
|
||||
|
||||
Walk the list once and handle each part in turn. No sort, so the cost drops to `O(n)`.
|
||||
|
||||
:::note[Intervals]
|
||||
`[[1,2], [3,5], [6,7], [8,10], [12,16]]`
|
||||
:::
|
||||
|
||||
:::note[New interval]
|
||||
`[4,8]`
|
||||
:::
|
||||
|
||||
```python
|
||||
# Time: O(n)
|
||||
# Space: O(n)
|
||||
def insert_interval(intervals, new_interval):
|
||||
result = []
|
||||
i, n = 0, len(intervals)
|
||||
start, end = new_interval
|
||||
|
||||
# 1. Ends before new starts: keep
|
||||
while i < n and intervals[i][1] < start:
|
||||
result.append(intervals[i])
|
||||
i += 1
|
||||
|
||||
# 2. Overlaps new: grow new to cover it
|
||||
while i < n and intervals[i][0] <= end:
|
||||
start = min(start, intervals[i][0])
|
||||
end = max(end, intervals[i][1])
|
||||
i += 1
|
||||
result.append([start, end])
|
||||
|
||||
# 3. Starts after new ends: keep
|
||||
result.extend(intervals[i:])
|
||||
return result
|
||||
```
|
||||
|
||||
<Expandable title="Show trace table">
|
||||
|
||||
|
||||
| i | interval | Part | Check | Action | `[start, end]` | `result` after |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 0 | `[1,2]` | 1 | `2 < 4` ✅ | keep | `[4,8]` | `[[1,2]]` |
|
||||
| 1 | `[3,5]` | 1 | `5 < 4` ❌ | go to part 2 | `[4,8]` | `[[1,2]]` |
|
||||
| 1 | `[3,5]` | 2 | `3 <= 8` ✅ | start = `min(4,3)` = 3 | `[3,8]` | `[[1,2]]` |
|
||||
| 2 | `[6,7]` | 2 | `6 <= 8` ✅ | end = `max(8,7)` = 8 | `[3,8]` | `[[1,2]]` |
|
||||
| 3 | `[8,10]` | 2 | `8 <= 8` ✅ | end = `max(8,10)` = 10 | `[3,10]` | `[[1,2]]` |
|
||||
| 4 | `[12,16]` | 2 | `12 <= 10` ❌ | append new | `[3,10]` | `[[1,2], [3,10]]` |
|
||||
| 4 | `[12,16]` | 3 | — | extend rest | — | `[[1,2], [3,10], [12,16]]` |
|
||||
|
||||
:::tip[Output]
|
||||
`[[1,2], [3,10], [12,16]]`
|
||||
- **Row i=1:** The same interval shows up twice. The part 1 check fails, so that loop stops, and part 2 reads the same interval again. `i` does not move.
|
||||
- **Row i=3:** `[8,10]` only touches `[3,8]` at 8. The `<=` merges them, since one shared point counts as an overlap.
|
||||
- **Part 1 uses `<`, part 2 uses `<=`:** An interval that ends exactly at `start` touches the new interval. It must fail part 1 so part 2 can merge it.
|
||||
:::
|
||||
|
||||
</Expandable>
|
||||
|
||||
:::warning
|
||||
If the input is already sorted, do not sort again. Interviewers add "sorted" to the problem on purpose. Name the `O(n log n)` cost of re-sorting before they do, then offer the `O(n)` three-part walk.
|
||||
:::
|
||||
|
||||
### Footnote
|
||||
|
||||
The positive overlap test comes straight from De Morgan's law. Negating `(a.end < b.start)` or `(b.end < a.start)` gives `(a.end >= b.start)` and `(b.end >= a.start)`, which is the `a.start <= b.end` and `b.start <= a.end` condition rewritten.
|
||||
@@ -0,0 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Intervals", order: 24, icon: "calendar-range", display: "page" });
|
||||
Reference in new issue
Block a user