Skip to content

Commit 2800255

Browse files
authored
feat: add solutions to lc problem: No.0435 (#4278)
1 parent a742201 commit 2800255

File tree

9 files changed

+137
-286
lines changed

9 files changed

+137
-286
lines changed

solution/0400-0499/0435.Non-overlapping Intervals/README.md

+48-108
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,18 @@ tags:
6565

6666
<!-- solution:start -->
6767

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

70-
最长上升子序列问题,动态规划的做法,时间复杂度是 $O(n^2)$,这里可以采用贪心优化,将复杂度降至 $O(n\log n)$。
70+
我们首先将区间按照右边界升序排序,用一个变量 $\textit{pre}$ 记录上一个区间的右边界,用一个变量 $\textit{ans}$ 记录需要移除的区间数量,初始时 $\textit{ans} = \textit{intervals.length}$。
71+
72+
然后遍历区间,对于每一个区间:
73+
74+
- 若当前区间的左边界大于等于 $\textit{pre}$,说明该区间无需移除,直接更新 $\textit{pre}$ 为当前区间的右边界,然后将 $\textit{ans}$ 减一;
75+
- 否则,说明该区间需要移除,不需要更新 $\textit{pre}$ 和 $\textit{ans}$。
76+
77+
最后返回 $\textit{ans}$ 即可。
78+
79+
时间复杂度 $O(n \times \log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为区间的数量。
7180

7281
<!-- tabs:start -->
7382

@@ -77,12 +86,12 @@ tags:
7786
class Solution:
7887
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
7988
intervals.sort(key=lambda x: x[1])
80-
ans, t = 0, intervals[0][1]
81-
for s, e in intervals[1:]:
82-
if s >= t:
83-
t = e
84-
else:
85-
ans += 1
89+
ans = len(intervals)
90+
pre = -inf
91+
for l, r in intervals:
92+
if pre <= l:
93+
ans -= 1
94+
pre = r
8695
return ans
8796
```
8897

@@ -91,13 +100,14 @@ class Solution:
91100
```java
92101
class Solution {
93102
public int eraseOverlapIntervals(int[][] intervals) {
94-
Arrays.sort(intervals, Comparator.comparingInt(a -> a[1]));
95-
int t = intervals[0][1], ans = 0;
96-
for (int i = 1; i < intervals.length; ++i) {
97-
if (intervals[i][0] >= t) {
98-
t = intervals[i][1];
99-
} else {
100-
++ans;
103+
Arrays.sort(intervals, (a, b) -> a[1] - b[1]);
104+
int ans = intervals.length;
105+
int pre = Integer.MIN_VALUE;
106+
for (var e : intervals) {
107+
int l = e[0], r = e[1];
108+
if (pre <= l) {
109+
--ans;
110+
pre = r;
101111
}
102112
}
103113
return ans;
@@ -111,13 +121,17 @@ class Solution {
111121
class Solution {
112122
public:
113123
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
114-
sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) { return a[1] < b[1]; });
115-
int ans = 0, t = intervals[0][1];
116-
for (int i = 1; i < intervals.size(); ++i) {
117-
if (t <= intervals[i][0])
118-
t = intervals[i][1];
119-
else
120-
++ans;
124+
ranges::sort(intervals, [](const vector<int>& a, const vector<int>& b) {
125+
return a[1] < b[1];
126+
});
127+
int ans = intervals.size();
128+
int pre = INT_MIN;
129+
for (const auto& e : intervals) {
130+
int l = e[0], r = e[1];
131+
if (pre <= l) {
132+
--ans;
133+
pre = r;
134+
}
121135
}
122136
return ans;
123137
}
@@ -131,12 +145,13 @@ func eraseOverlapIntervals(intervals [][]int) int {
131145
sort.Slice(intervals, func(i, j int) bool {
132146
return intervals[i][1] < intervals[j][1]
133147
})
134-
t, ans := intervals[0][1], 0
135-
for i := 1; i < len(intervals); i++ {
136-
if intervals[i][0] >= t {
137-
t = intervals[i][1]
138-
} else {
139-
ans++
148+
ans := len(intervals)
149+
pre := math.MinInt32
150+
for _, e := range intervals {
151+
l, r := e[0], e[1]
152+
if pre <= l {
153+
ans--
154+
pre = r
140155
}
141156
}
142157
return ans
@@ -148,14 +163,11 @@ func eraseOverlapIntervals(intervals [][]int) int {
148163
```ts
149164
function eraseOverlapIntervals(intervals: number[][]): number {
150165
intervals.sort((a, b) => a[1] - b[1]);
151-
let end = intervals[0][1],
152-
ans = 0;
153-
for (let i = 1; i < intervals.length; ++i) {
154-
let cur = intervals[i];
155-
if (end > cur[0]) {
156-
ans++;
157-
} else {
158-
end = cur[1];
166+
let [ans, pre] = [intervals.length, -Infinity];
167+
for (const [l, r] of intervals) {
168+
if (pre <= l) {
169+
--ans;
170+
pre = r;
159171
}
160172
}
161173
return ans;
@@ -166,76 +178,4 @@ function eraseOverlapIntervals(intervals: number[][]): number {
166178

167179
<!-- solution:end -->
168180

169-
<!-- solution:start -->
170-
171-
### 方法二:排序 + 贪心
172-
173-
先按照区间右边界排序。优先选择最小的区间的右边界作为起始边界。遍历区间:
174-
175-
- 若当前区间左边界大于等于起始右边界,说明该区间无需移除,直接更新起始右边界;
176-
- 否则说明该区间需要移除,更新移除区间的数量 ans。
177-
178-
最后返回 ans 即可。
179-
180-
时间复杂度 $O(n\log n)$。
181-
182-
<!-- tabs:start -->
183-
184-
#### Python3
185-
186-
```python
187-
class Solution:
188-
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
189-
intervals.sort()
190-
d = [intervals[0][1]]
191-
for s, e in intervals[1:]:
192-
if s >= d[-1]:
193-
d.append(e)
194-
else:
195-
idx = bisect_left(d, s)
196-
d[idx] = min(d[idx], e)
197-
return len(intervals) - len(d)
198-
```
199-
200-
#### Java
201-
202-
```java
203-
class Solution {
204-
public int eraseOverlapIntervals(int[][] intervals) {
205-
Arrays.sort(intervals, (a, b) -> {
206-
if (a[0] != b[0]) {
207-
return a[0] - b[0];
208-
}
209-
return a[1] - b[1];
210-
});
211-
int n = intervals.length;
212-
int[] d = new int[n + 1];
213-
d[1] = intervals[0][1];
214-
int size = 1;
215-
for (int i = 1; i < n; ++i) {
216-
int s = intervals[i][0], e = intervals[i][1];
217-
if (s >= d[size]) {
218-
d[++size] = e;
219-
} else {
220-
int left = 1, right = size;
221-
while (left < right) {
222-
int mid = (left + right) >> 1;
223-
if (d[mid] >= s) {
224-
right = mid;
225-
} else {
226-
left = mid + 1;
227-
}
228-
}
229-
d[left] = Math.min(d[left], e);
230-
}
231-
}
232-
return n - size;
233-
}
234-
}
235-
```
236-
237-
<!-- tabs:end -->
238-
239-
<!-- solution:end -->
240-
241181
<!-- problem:end -->

solution/0400-0499/0435.Non-overlapping Intervals/README_EN.md

+49-98
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,18 @@ tags:
6363

6464
<!-- solution:start -->
6565

66-
### Solution 1
66+
### Solution 1: Sorting + Greedy
67+
68+
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}$.
69+
70+
Then we iterate through the intervals. For each interval:
71+
72+
- 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;
73+
- Otherwise, it means that this interval needs to be removed, and we do not need to update $\textit{pre}$ and $\textit{ans}$.
74+
75+
Finally, we return $\textit{ans}$.
76+
77+
The time complexity is $O(n \times \log n)$, and the space complexity is $O(\log n)$, where $n$ is the number of intervals.
6778

6879
<!-- tabs:start -->
6980

@@ -73,12 +84,12 @@ tags:
7384
class Solution:
7485
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
7586
intervals.sort(key=lambda x: x[1])
76-
ans, t = 0, intervals[0][1]
77-
for s, e in intervals[1:]:
78-
if s >= t:
79-
t = e
80-
else:
81-
ans += 1
87+
ans = len(intervals)
88+
pre = -inf
89+
for l, r in intervals:
90+
if pre <= l:
91+
ans -= 1
92+
pre = r
8293
return ans
8394
```
8495

@@ -87,13 +98,14 @@ class Solution:
8798
```java
8899
class Solution {
89100
public int eraseOverlapIntervals(int[][] intervals) {
90-
Arrays.sort(intervals, Comparator.comparingInt(a -> a[1]));
91-
int t = intervals[0][1], ans = 0;
92-
for (int i = 1; i < intervals.length; ++i) {
93-
if (intervals[i][0] >= t) {
94-
t = intervals[i][1];
95-
} else {
96-
++ans;
101+
Arrays.sort(intervals, (a, b) -> a[1] - b[1]);
102+
int ans = intervals.length;
103+
int pre = Integer.MIN_VALUE;
104+
for (var e : intervals) {
105+
int l = e[0], r = e[1];
106+
if (pre <= l) {
107+
--ans;
108+
pre = r;
97109
}
98110
}
99111
return ans;
@@ -107,13 +119,17 @@ class Solution {
107119
class Solution {
108120
public:
109121
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
110-
sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) { return a[1] < b[1]; });
111-
int ans = 0, t = intervals[0][1];
112-
for (int i = 1; i < intervals.size(); ++i) {
113-
if (t <= intervals[i][0])
114-
t = intervals[i][1];
115-
else
116-
++ans;
122+
ranges::sort(intervals, [](const vector<int>& a, const vector<int>& b) {
123+
return a[1] < b[1];
124+
});
125+
int ans = intervals.size();
126+
int pre = INT_MIN;
127+
for (const auto& e : intervals) {
128+
int l = e[0], r = e[1];
129+
if (pre <= l) {
130+
--ans;
131+
pre = r;
132+
}
117133
}
118134
return ans;
119135
}
@@ -127,12 +143,13 @@ func eraseOverlapIntervals(intervals [][]int) int {
127143
sort.Slice(intervals, func(i, j int) bool {
128144
return intervals[i][1] < intervals[j][1]
129145
})
130-
t, ans := intervals[0][1], 0
131-
for i := 1; i < len(intervals); i++ {
132-
if intervals[i][0] >= t {
133-
t = intervals[i][1]
134-
} else {
135-
ans++
146+
ans := len(intervals)
147+
pre := math.MinInt32
148+
for _, e := range intervals {
149+
l, r := e[0], e[1]
150+
if pre <= l {
151+
ans--
152+
pre = r
136153
}
137154
}
138155
return ans
@@ -144,14 +161,11 @@ func eraseOverlapIntervals(intervals [][]int) int {
144161
```ts
145162
function eraseOverlapIntervals(intervals: number[][]): number {
146163
intervals.sort((a, b) => a[1] - b[1]);
147-
let end = intervals[0][1],
148-
ans = 0;
149-
for (let i = 1; i < intervals.length; ++i) {
150-
let cur = intervals[i];
151-
if (end > cur[0]) {
152-
ans++;
153-
} else {
154-
end = cur[1];
164+
let [ans, pre] = [intervals.length, -Infinity];
165+
for (const [l, r] of intervals) {
166+
if (pre <= l) {
167+
--ans;
168+
pre = r;
155169
}
156170
}
157171
return ans;
@@ -162,67 +176,4 @@ function eraseOverlapIntervals(intervals: number[][]): number {
162176

163177
<!-- solution:end -->
164178

165-
<!-- solution:start -->
166-
167-
### Solution 2
168-
169-
<!-- tabs:start -->
170-
171-
#### Python3
172-
173-
```python
174-
class Solution:
175-
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
176-
intervals.sort()
177-
d = [intervals[0][1]]
178-
for s, e in intervals[1:]:
179-
if s >= d[-1]:
180-
d.append(e)
181-
else:
182-
idx = bisect_left(d, s)
183-
d[idx] = min(d[idx], e)
184-
return len(intervals) - len(d)
185-
```
186-
187-
#### Java
188-
189-
```java
190-
class Solution {
191-
public int eraseOverlapIntervals(int[][] intervals) {
192-
Arrays.sort(intervals, (a, b) -> {
193-
if (a[0] != b[0]) {
194-
return a[0] - b[0];
195-
}
196-
return a[1] - b[1];
197-
});
198-
int n = intervals.length;
199-
int[] d = new int[n + 1];
200-
d[1] = intervals[0][1];
201-
int size = 1;
202-
for (int i = 1; i < n; ++i) {
203-
int s = intervals[i][0], e = intervals[i][1];
204-
if (s >= d[size]) {
205-
d[++size] = e;
206-
} else {
207-
int left = 1, right = size;
208-
while (left < right) {
209-
int mid = (left + right) >> 1;
210-
if (d[mid] >= s) {
211-
right = mid;
212-
} else {
213-
left = mid + 1;
214-
}
215-
}
216-
d[left] = Math.min(d[left], e);
217-
}
218-
}
219-
return n - size;
220-
}
221-
}
222-
```
223-
224-
<!-- tabs:end -->
225-
226-
<!-- solution:end -->
227-
228179
<!-- problem:end -->

0 commit comments

Comments
 (0)