Description

給定一個正整數陣列 nums,你可以對任意元素執行以下操作任意次:若元素為偶數,可以除以 2;若元素為奇數,可以乘以 2。求陣列中最大值與最小值之差(deviation)的最小可能值。

Example:

Input: nums = [1,2,3,4] Output: 1

Intuition#

核心思路:先把所有數都變成最大值(奇數乘 2),然後用 Max Heap 不斷縮小最大值,追蹤最小 deviation。

  • 奇數只能乘以 2 一次(變偶數),偶數可以一直除以 2 直到變奇數
  • 統一策略:先把所有奇數乘 2(變成各自的最大可能值),這樣每個數只能往下縮
  • 用 Max Heap 追蹤當前最大值,同時記錄全域最小值
  • 每次把最大值除以 2(只有偶數才能除),更新 deviation,直到最大值為奇數時停止

Approaches#

⭐1: Max Heap + Greedy#

  • 概念: 將所有奇數先乘 2 推入 Max Heap,追蹤最小值。每次取出最大值,若為偶數則除以 2 後放回,更新 deviation
  • 時間複雜度: O(n * log(maxVal) * log n) - 每個元素最多被除 log(maxVal) 次,每次 heap 操作 O(log n)
  • 空間複雜度: O(n)
class Solution {
    fun minimumDeviation(nums: IntArray): Int {
        val maxHeap = PriorityQueue<Int>(compareByDescending { it })
        var minVal = Int.MAX_VALUE

        for (num in nums) {
            val val_ = if (num % 2 == 1) num * 2 else num
            maxHeap.offer(val_)
            minVal = minOf(minVal, val_)
        }

        var result = maxHeap.peek() - minVal

        while (maxHeap.peek() % 2 == 0) {
            val maxVal = maxHeap.poll()
            val halved = maxVal / 2
            maxHeap.offer(halved)
            minVal = minOf(minVal, halved)
            result = minOf(result, maxHeap.peek() - minVal)
        }

        return result
    }
}

🔑 Takeaways#

  • Pattern: 先統一方向(全部拉到最大),再用 Heap 貪心地逐步縮小範圍
  • 關鍵技巧: 奇偶操作的不對稱性——先把奇數乘 2 統一成偶數,讓所有數都只能往下除;Max Heap 頂部偶數才能繼續除,奇數到頂時即為終止條件