From 8117d3634916b0b8bf50708ea92879140c67acdf Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Fri, 21 Mar 2025 20:45:54 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.0435 No.0435.Non-overlapping Intervals --- .../0435.Non-overlapping Intervals/README.md | 156 ++++++------------ .../README_EN.md | 147 ++++++----------- .../Solution.cpp | 20 ++- .../Solution.go | 15 +- .../Solution.java | 17 +- .../Solution.py | 12 +- .../Solution.ts | 13 +- .../Solution2.java | 32 ---- .../Solution2.py | 11 -- 9 files changed, 137 insertions(+), 286 deletions(-) delete mode 100644 solution/0400-0499/0435.Non-overlapping Intervals/Solution2.java delete mode 100644 solution/0400-0499/0435.Non-overlapping Intervals/Solution2.py diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/README.md b/solution/0400-0499/0435.Non-overlapping Intervals/README.md index d11d9c230875c..239271f1d1323 100644 --- a/solution/0400-0499/0435.Non-overlapping Intervals/README.md +++ b/solution/0400-0499/0435.Non-overlapping Intervals/README.md @@ -65,9 +65,18 @@ tags: -### 方法一:转换为最长上升子序列问题 +### 方法一:排序 + 贪心 -最长上升子序列问题,动态规划的做法,时间复杂度是 $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$ 为区间的数量。 @@ -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 ``` @@ -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; @@ -111,13 +121,17 @@ class Solution { class Solution { public: int eraseOverlapIntervals(vector>& 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& a, const vector& 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; } @@ -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 @@ -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; @@ -166,76 +178,4 @@ function eraseOverlapIntervals(intervals: number[][]): number { - - -### 方法二:排序 + 贪心 - -先按照区间右边界排序。优先选择最小的区间的右边界作为起始边界。遍历区间: - -- 若当前区间左边界大于等于起始右边界,说明该区间无需移除,直接更新起始右边界; -- 否则说明该区间需要移除,更新移除区间的数量 ans。 - -最后返回 ans 即可。 - -时间复杂度 $O(n\log n)$。 - - - -#### 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; - } -} -``` - - - - - diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/README_EN.md b/solution/0400-0499/0435.Non-overlapping Intervals/README_EN.md index d4ea312a3852c..61a99a2fbd245 100644 --- a/solution/0400-0499/0435.Non-overlapping Intervals/README_EN.md +++ b/solution/0400-0499/0435.Non-overlapping Intervals/README_EN.md @@ -63,7 +63,18 @@ tags: -### 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. @@ -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 ``` @@ -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; @@ -107,13 +119,17 @@ class Solution { class Solution { public: int eraseOverlapIntervals(vector>& 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& a, const vector& 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; } @@ -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 @@ -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; @@ -162,67 +176,4 @@ function eraseOverlapIntervals(intervals: number[][]): number { - - -### Solution 2 - - - -#### 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; - } -} -``` - - - - - diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.cpp b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.cpp index e754f1db36a3a..f362aa4fee404 100644 --- a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.cpp +++ b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.cpp @@ -1,14 +1,18 @@ class Solution { public: int eraseOverlapIntervals(vector>& 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& a, const vector& 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; } -}; \ No newline at end of file +}; diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.go b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.go index d40eb5b6378ed..16085cd32cfb7 100644 --- a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.go +++ b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.go @@ -2,13 +2,14 @@ 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 -} \ No newline at end of file +} diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.java b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.java index 06940f1be5f62..907073e547ef1 100644 --- a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.java +++ b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.java @@ -1,14 +1,15 @@ 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; } -} \ No newline at end of file +} diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.py b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.py index d599421163958..55d4b26112c33 100644 --- a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.py +++ b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.py @@ -1,10 +1,10 @@ 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 diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.ts b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.ts index d10fa2a880de6..9e6ced4c9275e 100644 --- a/solution/0400-0499/0435.Non-overlapping Intervals/Solution.ts +++ b/solution/0400-0499/0435.Non-overlapping Intervals/Solution.ts @@ -1,13 +1,10 @@ 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; diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/Solution2.java b/solution/0400-0499/0435.Non-overlapping Intervals/Solution2.java deleted file mode 100644 index 3db74098111b5..0000000000000 --- a/solution/0400-0499/0435.Non-overlapping Intervals/Solution2.java +++ /dev/null @@ -1,32 +0,0 @@ -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; - } -} \ No newline at end of file diff --git a/solution/0400-0499/0435.Non-overlapping Intervals/Solution2.py b/solution/0400-0499/0435.Non-overlapping Intervals/Solution2.py deleted file mode 100644 index 8b41845673b4f..0000000000000 --- a/solution/0400-0499/0435.Non-overlapping Intervals/Solution2.py +++ /dev/null @@ -1,11 +0,0 @@ -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)