Medium草稿★★★★★O(n log n + n log(max-min)) 時間 · O(1) 空間
ArrayBinary SearchGreedy
Patterns📐 二分答案🎯 二分搜尋🪙 貪心
尚未複習過

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

2616Minimize the Maximum Difference of PairsBinary SearchMediumBinary Search

給定一個整數陣列 nums 和整數 p。從陣列中選出 p 對不重疊的索引對,使得這 p 對中最大差值最小化。回傳這個最小化後的最大差值。

Example:

Input: nums = [10,1,2,7,1,3], p = 2 Output: 1(選 (1,4) 和 (2,5),差值分別為 0 和 1,最大差值為 1)

Intuition

TIP

排序後,在答案空間 [0, max-min] 上二分搜尋最大差值,用貪心驗證是否能找到 p 對。

Approaches

1. Brute Force: Try Each Threshold Ascending — O(n log n + n·(max-min)) / O(1)
  • Idea: 排序後從 0 起線性試每個差值上限,第一個能湊到 p 對的即答案
  • Time: O(n log n + n·(max-min)) - 值域線性掃描、每次貪心驗證 O(n)
  • Space: O(1)(不計排序)
class Solution {
    fun minimizeMax(nums: IntArray, p: Int): Int {
        if (p == 0) return 0
        nums.sort()
        val maxDiff = nums.last() - nums.first()
        for (threshold in 0..maxDiff) {
            if (canFormPairs(nums, p, threshold)) return threshold
        }
        return maxDiff
    }

    private fun canFormPairs(nums: IntArray, p: Int, threshold: Int): Boolean {
        var count = 0
        var i = 0
        while (i < nums.size - 1) {
            if (nums[i + 1] - nums[i] <= threshold) { count++; i += 2 } else i++
            if (count >= p) return true
        }
        return count >= p
    }
}
⭐ 2. Binary Search on Answer + Greedy Check — O(n log n + n log(max-min)) / O(1)
  • Idea: 排序後在 [0, max-min] 上二分搜尋,對每個候選值貪心檢查是否可行
  • Time: O(n log n + n log(max-min))
  • Space: O(1)(不計排序空間)
class Solution {
    fun minimizeMax(nums: IntArray, p: Int): Int {
        if (p == 0) return 0
        nums.sort()
        var left = 0
        var right = nums.last() - nums.first()
        while (left < right) {
            val mid = left + (right - left) / 2
            if (canFormPairs(nums, p, mid)) {
                right = mid
            } else {
                left = mid + 1
            }
        }
        return left
    }

    private fun canFormPairs(nums: IntArray, p: Int, threshold: Int): Boolean {
        var count = 0
        var i = 0
        while (i < nums.size - 1) {
            if (nums[i + 1] - nums[i] <= threshold) {
                count++
                i += 2  // 跳過已配對的兩個元素
            } else {
                i++
            }
            if (count >= p) return true
        }
        return count >= p
    }
}

WARNING

貪心驗證的關鍵:排序後從左到右掃描,如果相鄰兩個差值 <= threshold 就配對並跳過兩個元素(i += 2),否則只跳過一個(i++)。

🔑 Takeaways