Description

給定一個二維陣列 intervalsintervals[i] = [left_i, right_i])和一個查詢陣列 queries。對每個查詢 q,找出包含 q 的最小區間長度(right - left + 1)。如果沒有區間包含 q,答案為 -1。

Example:

Input: intervals = [[1,4],[2,4],[3,6],[4,4]], queries = [2,3,4,5] Output: [3,3,1,4]

Intuition#

離線處理:將查詢排序後,配合排序的區間和 min-heap,逐步處理每個查詢。

  • 暴力對每個查詢檢查所有區間是 O(n * q),太慢
  • 離線排序:將查詢和區間都按位置排序
  • 用 min-heap 按區間長度排序,維護所有可能包含當前查詢的區間

Approaches#

1: Brute Force#

  • 概念: 對每個查詢遍歷所有區間,找包含它的最小區間
  • 時間複雜度: O(n * q) — n 為區間數,q 為查詢數
  • 空間複雜度: O(q) — 輸出空間
class Solution {
    fun minInterval(intervals: Array<IntArray>, queries: IntArray): IntArray {
        val result = IntArray(queries.size)
        for (i in queries.indices) {
            var minSize = Int.MAX_VALUE
            for (interval in intervals) {
                if (interval[0] <= queries[i] && queries[i] <= interval[1]) {
                    minSize = minOf(minSize, interval[1] - interval[0] + 1)
                }
            }
            result[i] = if (minSize == Int.MAX_VALUE) -1 else minSize
        }
        return result
    }
}

⭐2: Offline Sort + Min-Heap#

  • 概念: 將區間按起點排序,查詢按值排序(保留原始索引)。對每個查詢,將所有起點 <= 查詢值的區間加入 min-heap(按長度排序),再移除終點 < 查詢值的無效區間,堆頂即為答案。
  • 時間複雜度: O((n + q) log n)
  • 空間複雜度: O(n + q)
class Solution {
    fun minInterval(intervals: Array<IntArray>, queries: IntArray): IntArray {
        // 區間按起點排序
        intervals.sortBy { it[0] }

        // 查詢排序但保留原始索引
        val sortedQueries = queries.indices.sortedBy { queries[it] }

        // min-heap: (區間長度, 區間終點)
        val heap = java.util.PriorityQueue<IntArray>(compareBy { it[0] })

        val result = IntArray(queries.size) { -1 }
        var idx = 0

        for (qi in sortedQueries) {
            val q = queries[qi]

            // 將所有起點 <= q 的區間加入 heap
            while (idx < intervals.size && intervals[idx][0] <= q) {
                val size = intervals[idx][1] - intervals[idx][0] + 1
                heap.add(intArrayOf(size, intervals[idx][1]))
                idx++
            }

            // 移除終點 < q 的區間(不再包含 q)
            while (heap.isNotEmpty() && heap.peek()[1] < q) {
                heap.poll()
            }

            if (heap.isNotEmpty()) {
                result[qi] = heap.peek()[0]
            }
        }

        return result
    }
}

🔑 Takeaways#

  • Pattern: 離線查詢 + Sweep — 當查詢可以排序處理時,離線排序配合堆可以大幅降低複雜度
  • 關鍵技巧: 離線處理的核心是「排序後單調推進」:區間只會被加入 heap 一次,也只會被移除一次,攤平後每個操作都是 O(log n)