Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add solutions to lc problem: No.0435 #4278

Merged
merged 1 commit into from
Mar 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: add solutions to lc problem: No.0435
No.0435.Non-overlapping Intervals
  • Loading branch information
yanglbme committed Mar 21, 2025
commit 8117d3634916b0b8bf50708ea92879140c67acdf
156 changes: 48 additions & 108 deletions solution/0400-0499/0435.Non-overlapping Intervals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,18 @@ tags:

<!-- solution:start -->

### 方法一:转换为最长上升子序列问题
### 方法一:排序 + 贪心

最长上升子序列问题,动态规划的做法,时间复杂度是 $O(n^2)$,这里可以采用贪心优化,将复杂度降至 $O(n\log n)$。
我们首先将区间按照右边界升序排序,用一个变量 $\textit{pre}$ 记录上一个区间的右边界,用一个变量 $\textit{ans}$ 记录需要移除的区间数量,初始时 $\textit{ans} = \textit{intervals.length}$。

然后遍历区间,对于每一个区间:

- 若当前区间的左边界大于等于 $\textit{pre}$,说明该区间无需移除,直接更新 $\textit{pre}$ 为当前区间的右边界,然后将 $\textit{ans}$ 减一;
- 否则,说明该区间需要移除,不需要更新 $\textit{pre}$ 和 $\textit{ans}$。

最后返回 $\textit{ans}$ 即可。

时间复杂度 $O(n \times \log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为区间的数量。

<!-- tabs:start -->

Expand All @@ -77,12 +86,12 @@ tags:
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort(key=lambda x: x[1])
ans, t = 0, intervals[0][1]
for s, e in intervals[1:]:
if s >= t:
t = e
else:
ans += 1
ans = len(intervals)
pre = -inf
for l, r in intervals:
if pre <= l:
ans -= 1
pre = r
return ans
```

Expand All @@ -91,13 +100,14 @@ class Solution:
```java
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, Comparator.comparingInt(a -> a[1]));
int t = intervals[0][1], ans = 0;
for (int i = 1; i < intervals.length; ++i) {
if (intervals[i][0] >= t) {
t = intervals[i][1];
} else {
++ans;
Arrays.sort(intervals, (a, b) -> a[1] - b[1]);
int ans = intervals.length;
int pre = Integer.MIN_VALUE;
for (var e : intervals) {
int l = e[0], r = e[1];
if (pre <= l) {
--ans;
pre = r;
}
}
return ans;
Expand All @@ -111,13 +121,17 @@ class Solution {
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) { return a[1] < b[1]; });
int ans = 0, t = intervals[0][1];
for (int i = 1; i < intervals.size(); ++i) {
if (t <= intervals[i][0])
t = intervals[i][1];
else
++ans;
ranges::sort(intervals, [](const vector<int>& a, const vector<int>& b) {
return a[1] < b[1];
});
int ans = intervals.size();
int pre = INT_MIN;
for (const auto& e : intervals) {
int l = e[0], r = e[1];
if (pre <= l) {
--ans;
pre = r;
}
}
return ans;
}
Expand All @@ -131,12 +145,13 @@ func eraseOverlapIntervals(intervals [][]int) int {
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][1] < intervals[j][1]
})
t, ans := intervals[0][1], 0
for i := 1; i < len(intervals); i++ {
if intervals[i][0] >= t {
t = intervals[i][1]
} else {
ans++
ans := len(intervals)
pre := math.MinInt32
for _, e := range intervals {
l, r := e[0], e[1]
if pre <= l {
ans--
pre = r
}
}
return ans
Expand All @@ -148,14 +163,11 @@ func eraseOverlapIntervals(intervals [][]int) int {
```ts
function eraseOverlapIntervals(intervals: number[][]): number {
intervals.sort((a, b) => a[1] - b[1]);
let end = intervals[0][1],
ans = 0;
for (let i = 1; i < intervals.length; ++i) {
let cur = intervals[i];
if (end > cur[0]) {
ans++;
} else {
end = cur[1];
let [ans, pre] = [intervals.length, -Infinity];
for (const [l, r] of intervals) {
if (pre <= l) {
--ans;
pre = r;
}
}
return ans;
Expand All @@ -166,76 +178,4 @@ function eraseOverlapIntervals(intervals: number[][]): number {

<!-- solution:end -->

<!-- solution:start -->

### 方法二:排序 + 贪心

先按照区间右边界排序。优先选择最小的区间的右边界作为起始边界。遍历区间:

- 若当前区间左边界大于等于起始右边界,说明该区间无需移除,直接更新起始右边界;
- 否则说明该区间需要移除,更新移除区间的数量 ans。

最后返回 ans 即可。

时间复杂度 $O(n\log n)$。

<!-- tabs:start -->

#### Python3

```python
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort()
d = [intervals[0][1]]
for s, e in intervals[1:]:
if s >= d[-1]:
d.append(e)
else:
idx = bisect_left(d, s)
d[idx] = min(d[idx], e)
return len(intervals) - len(d)
```

#### Java

```java
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> {
if (a[0] != b[0]) {
return a[0] - b[0];
}
return a[1] - b[1];
});
int n = intervals.length;
int[] d = new int[n + 1];
d[1] = intervals[0][1];
int size = 1;
for (int i = 1; i < n; ++i) {
int s = intervals[i][0], e = intervals[i][1];
if (s >= d[size]) {
d[++size] = e;
} else {
int left = 1, right = size;
while (left < right) {
int mid = (left + right) >> 1;
if (d[mid] >= s) {
right = mid;
} else {
left = mid + 1;
}
}
d[left] = Math.min(d[left], e);
}
}
return n - size;
}
}
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- problem:end -->
147 changes: 49 additions & 98 deletions solution/0400-0499/0435.Non-overlapping Intervals/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,18 @@ tags:

<!-- solution:start -->

### Solution 1
### Solution 1: Sorting + Greedy

We first sort the intervals in ascending order by their right boundary. We use a variable $\textit{pre}$ to record the right boundary of the previous interval and a variable $\textit{ans}$ to record the number of intervals that need to be removed. Initially, $\textit{ans} = \textit{intervals.length}$.

Then we iterate through the intervals. For each interval:

- If the left boundary of the current interval is greater than or equal to $\textit{pre}$, it means that this interval does not need to be removed. We directly update $\textit{pre}$ to the right boundary of the current interval and decrement $\textit{ans}$ by one;
- Otherwise, it means that this interval needs to be removed, and we do not need to update $\textit{pre}$ and $\textit{ans}$.

Finally, we return $\textit{ans}$.

The time complexity is $O(n \times \log n)$, and the space complexity is $O(\log n)$, where $n$ is the number of intervals.

<!-- tabs:start -->

Expand All @@ -73,12 +84,12 @@ tags:
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort(key=lambda x: x[1])
ans, t = 0, intervals[0][1]
for s, e in intervals[1:]:
if s >= t:
t = e
else:
ans += 1
ans = len(intervals)
pre = -inf
for l, r in intervals:
if pre <= l:
ans -= 1
pre = r
return ans
```

Expand All @@ -87,13 +98,14 @@ class Solution:
```java
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, Comparator.comparingInt(a -> a[1]));
int t = intervals[0][1], ans = 0;
for (int i = 1; i < intervals.length; ++i) {
if (intervals[i][0] >= t) {
t = intervals[i][1];
} else {
++ans;
Arrays.sort(intervals, (a, b) -> a[1] - b[1]);
int ans = intervals.length;
int pre = Integer.MIN_VALUE;
for (var e : intervals) {
int l = e[0], r = e[1];
if (pre <= l) {
--ans;
pre = r;
}
}
return ans;
Expand All @@ -107,13 +119,17 @@ class Solution {
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) { return a[1] < b[1]; });
int ans = 0, t = intervals[0][1];
for (int i = 1; i < intervals.size(); ++i) {
if (t <= intervals[i][0])
t = intervals[i][1];
else
++ans;
ranges::sort(intervals, [](const vector<int>& a, const vector<int>& b) {
return a[1] < b[1];
});
int ans = intervals.size();
int pre = INT_MIN;
for (const auto& e : intervals) {
int l = e[0], r = e[1];
if (pre <= l) {
--ans;
pre = r;
}
}
return ans;
}
Expand All @@ -127,12 +143,13 @@ func eraseOverlapIntervals(intervals [][]int) int {
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][1] < intervals[j][1]
})
t, ans := intervals[0][1], 0
for i := 1; i < len(intervals); i++ {
if intervals[i][0] >= t {
t = intervals[i][1]
} else {
ans++
ans := len(intervals)
pre := math.MinInt32
for _, e := range intervals {
l, r := e[0], e[1]
if pre <= l {
ans--
pre = r
}
}
return ans
Expand All @@ -144,14 +161,11 @@ func eraseOverlapIntervals(intervals [][]int) int {
```ts
function eraseOverlapIntervals(intervals: number[][]): number {
intervals.sort((a, b) => a[1] - b[1]);
let end = intervals[0][1],
ans = 0;
for (let i = 1; i < intervals.length; ++i) {
let cur = intervals[i];
if (end > cur[0]) {
ans++;
} else {
end = cur[1];
let [ans, pre] = [intervals.length, -Infinity];
for (const [l, r] of intervals) {
if (pre <= l) {
--ans;
pre = r;
}
}
return ans;
Expand All @@ -162,67 +176,4 @@ function eraseOverlapIntervals(intervals: number[][]): number {

<!-- solution:end -->

<!-- solution:start -->

### Solution 2

<!-- tabs:start -->

#### Python3

```python
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort()
d = [intervals[0][1]]
for s, e in intervals[1:]:
if s >= d[-1]:
d.append(e)
else:
idx = bisect_left(d, s)
d[idx] = min(d[idx], e)
return len(intervals) - len(d)
```

#### Java

```java
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> {
if (a[0] != b[0]) {
return a[0] - b[0];
}
return a[1] - b[1];
});
int n = intervals.length;
int[] d = new int[n + 1];
d[1] = intervals[0][1];
int size = 1;
for (int i = 1; i < n; ++i) {
int s = intervals[i][0], e = intervals[i][1];
if (s >= d[size]) {
d[++size] = e;
} else {
int left = 1, right = size;
while (left < right) {
int mid = (left + right) >> 1;
if (d[mid] >= s) {
right = mid;
} else {
left = mid + 1;
}
}
d[left] = Math.min(d[left], e);
}
}
return n - size;
}
}
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- problem:end -->
Loading