Medium草稿★★★★★O(n log n) 時間 · O(log n) 空間
ArraySortingIntervals
Patterns📊 區間合併・排程🔢 排序後處理
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

1288Remove Covered IntervalsIntervalsMediumIntervals

給定一組區間 intervals,移除所有被其他區間完全覆蓋的區間。區間 [a,b)[c,d) 覆蓋的條件是 c <= ab <= d。回傳剩餘區間的數量。

Example:

Input: intervals = [[1,4],[3,6],[2,8]] Output: 2 ([1,4] 被 [2,8] 覆蓋,但 [2,8] 不被覆蓋所以實際是 [3,6] 和 [2,8]… 更正:[1,4] 被 [2,8] 覆蓋? 不,1 < 2。讓我重新看:[3,6] 被 [2,8] 覆蓋因為 2<=3 且 6<=8)

Intuition

TIP

核心思路:按起點升序排序(起點相同則按終點降序),然後追蹤目前最大的右端點,若新區間的右端點不超過它就是被覆蓋的。

Approaches

⭐ 1. Sort + Greedy — O(n log n) / O(log n)
  • Idea: 排序後線性掃描,用 maxRight 追蹤覆蓋範圍
  • Time: O(n log n) - 排序主導
  • Space: O(log n) - 排序空間
class Solution {
    fun removeCoveredIntervals(intervals: Array<IntArray>): Int {
        // 起點升序,起點相同則終點降序
        intervals.sortWith(compareBy<IntArray> { it[0] }.thenByDescending { it[1] })

        var count = 0
        var maxRight = 0

        for (interval in intervals) {
            if (interval[1] > maxRight) {
                // 不被覆蓋
                count++
                maxRight = interval[1]
            }
            // 否則 interval[1] <= maxRight,被前面的區間覆蓋
        }

        return count
    }
}
2. Brute Force: Pairwise Compare — O(n^2) / O(1)
  • Idea: 對每個區間檢查是否存在另一個區間覆蓋它
  • Time: O(n^2) - 兩層迴圈
  • Space: O(1)
class Solution {
    fun removeCoveredIntervals(intervals: Array<IntArray>): Int {
        val n = intervals.size
        var removed = 0

        for (i in 0 until n) {
            var covered = false
            for (j in 0 until n) {
                if (i != j &&
                    intervals[j][0] <= intervals[i][0] &&
                    intervals[i][1] <= intervals[j][1]) {
                    covered = true
                    break
                }
            }
            if (covered) removed++
        }

        return n - removed
    }
}

🔑 Takeaways