diff --git a/solution/0700-0799/0757.Set Intersection Size At Least Two/README.md b/solution/0700-0799/0757.Set Intersection Size At Least Two/README.md index df035077b0689..159abe08a9c2e 100644 --- a/solution/0700-0799/0757.Set Intersection Size At Least Two/README.md +++ b/solution/0700-0799/0757.Set Intersection Size At Least Two/README.md @@ -45,7 +45,7 @@ tags: 输入:intervals = [[1,3],[1,4],[2,5],[3,5]] 输出:3 解释:nums = [2, 3, 4]. -可以证明不存在元素数量为 2 的包含集合。 +可以证明不存在元素数量为 2 的包含集合。

示例 3:

@@ -54,7 +54,7 @@ tags: 输入:intervals = [[1,2],[2,3],[2,4],[4,5]] 输出:5 解释:nums = [1, 2, 3, 4, 5]. -可以证明不存在元素数量为 4 的包含集合。 +可以证明不存在元素数量为 4 的包含集合。

 

@@ -75,9 +75,31 @@ tags: ### 方法一:排序 + 贪心 -相似题目: +我们希望在数轴上选出尽可能少的整数点,使得每个区间都至少包含两个点。一个经典而有效的策略是按照区间的右端点进行排序,并尽量让已选取的点位于区间的右侧,以便这些点能覆盖更多后续区间。 + +首先将所有区间按照如下规则排序: + +1. 按右端点从小到大; +2. 若右端点相同,按左端点从大到小。 + +这样排序的原因是:右端点越小的区间“可操作空间”越少,应优先满足;当右端点相同时,左端点更大的区间更窄,更应优先被处理。 + +随后,我们使用两个变量 $s$ 和 $e$ 分别记录当前所有已处理区间所共同拥有的 **倒数第二个点** 和 **最后一个点**。初始时 $s = e = -1$,表示还没有放置任何点。 + +接下来依次处理排序后的区间 $[a, b]$,根据它与 $\{s, e\}$ 的关系分三种情况讨论: + +1. **若 $a \leq s$**: + 当前区间已包含 $s$ 和 $e$ 两个点,无需额外放点。 + +2. **若 $s < a \leq e$**: + 当前区间只包含一个点(即 $e$),还需要补一个点。为了让新点对后续区间最有帮助,我们选择在区间最右侧的点 $b$。此时更新 $\textit{ans} = \textit{ans} + 1$,并将新的两点设为 $\{e, b\}$。 -- [452. 用最少数量的箭引爆气球](https://github.com/doocs/leetcode/blob/main/solution/0400-0499/0452.Minimum%20Number%20of%20Arrows%20to%20Burst%20Balloons/README.md) +3. **若 $a > e$**: + 当前区间完全不包含已有的两个点,需要补两个点。最优选择是在区间最右侧放置 $\{b - 1, b\}$。此时更新 $\textit{ans} = \textit{ans} + 2$,并将新的两点设为 $\{b - 1, b\}$。 + +最终返回总共放置的点数 $\textit{ans}$。 + +时间复杂度 $O(n \times \log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为区间的数量。 @@ -188,6 +210,32 @@ func intersectionSizeTwo(intervals [][]int) int { } ``` +#### TypeScript + +```ts +function intersectionSizeTwo(intervals: number[][]): number { + intervals.sort((a, b) => (a[1] !== b[1] ? a[1] - b[1] : b[0] - a[0])); + let s = -1; + let e = -1; + let ans = 0; + for (const [a, b] of intervals) { + if (a <= s) { + continue; + } + if (a > e) { + ans += 2; + s = b - 1; + e = b; + } else { + ans += 1; + s = e; + e = b; + } + } + return ans; +} +``` + diff --git a/solution/0700-0799/0757.Set Intersection Size At Least Two/README_EN.md b/solution/0700-0799/0757.Set Intersection Size At Least Two/README_EN.md index 4c36ce0960c78..ece37611aec01 100644 --- a/solution/0700-0799/0757.Set Intersection Size At Least Two/README_EN.md +++ b/solution/0700-0799/0757.Set Intersection Size At Least Two/README_EN.md @@ -71,7 +71,33 @@ It can be shown that there cannot be any containing array of size 4. -### Solution 1 +### Solution 1: Sorting + Greedy + +We want to select as few integer points as possible on the number line such that each interval contains at least two points. A classic and effective strategy is to sort intervals by their right endpoints and try to place selected points towards the right side of intervals, so that these points can cover more subsequent intervals. + +First, sort all intervals by the following rules: + +1. Sort by right endpoint in ascending order; +2. If right endpoints are equal, sort by left endpoint in descending order. + +The reason for this sorting is: intervals with smaller right endpoints have less "operational space" and should be satisfied first; when right endpoints are equal, intervals with larger left endpoints are narrower and should be prioritized. + +Next, we use two variables $s$ and $e$ to record the **second-to-last point** and **last point** that are common to all currently processed intervals. Initially, $s = e = -1$, indicating that no points have been placed yet. + +Then we process the sorted intervals $[a, b]$ one by one, and discuss three cases based on their relationship with $\{s, e\}$: + +1. **If $a \leq s$**: + The current interval already contains both points $s$ and $e$, so no additional points are needed. + +2. **If $s < a \leq e$**: + The current interval only contains one point (i.e., $e$), and needs one more point. To make the new point most helpful for subsequent intervals, we choose the rightmost point $b$ in the interval. Update $\textit{ans} = \textit{ans} + 1$, and set the new two points to $\{e, b\}$. + +3. **If $a > e$**: + The current interval does not contain either of the existing two points, so two points need to be added. The optimal choice is to place $\{b - 1, b\}$ at the rightmost side of the interval. Update $\textit{ans} = \textit{ans} + 2$, and set the new two points to $\{b - 1, b\}$. + +Finally, return the total number of points placed, $\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. @@ -182,6 +208,32 @@ func intersectionSizeTwo(intervals [][]int) int { } ``` +#### TypeScript + +```ts +function intersectionSizeTwo(intervals: number[][]): number { + intervals.sort((a, b) => (a[1] !== b[1] ? a[1] - b[1] : b[0] - a[0])); + let s = -1; + let e = -1; + let ans = 0; + for (const [a, b] of intervals) { + if (a <= s) { + continue; + } + if (a > e) { + ans += 2; + s = b - 1; + e = b; + } else { + ans += 1; + s = e; + e = b; + } + } + return ans; +} +``` + diff --git a/solution/0700-0799/0757.Set Intersection Size At Least Two/Solution.ts b/solution/0700-0799/0757.Set Intersection Size At Least Two/Solution.ts new file mode 100644 index 0000000000000..9c1d11788cab0 --- /dev/null +++ b/solution/0700-0799/0757.Set Intersection Size At Least Two/Solution.ts @@ -0,0 +1,21 @@ +function intersectionSizeTwo(intervals: number[][]): number { + intervals.sort((a, b) => (a[1] !== b[1] ? a[1] - b[1] : b[0] - a[0])); + let s = -1; + let e = -1; + let ans = 0; + for (const [a, b] of intervals) { + if (a <= s) { + continue; + } + if (a > e) { + ans += 2; + s = b - 1; + e = b; + } else { + ans += 1; + s = e; + e = b; + } + } + return ans; +}