Description

給定不同整數的陣列 nums,重新排列使得每個元素都不等於其左右鄰居的平均值。

Example:

Input: nums = [1,2,3,4,5] Output: [1,2,4,5,3](任何合法排列皆可)

Intuition#

核心思路:排序後,交替放置較小和較大的元素(Wiggle Sort),保證每個元素不是鄰居的平均值。

  • 如果排成鋸齒狀(小、大、小、大…),每個「大」都大於兩邊,每個「小」都小於兩邊
  • 不等於平均值 = 不在兩個鄰居之間 = 比兩邊都大或都小
  • 排序後用 Two Pointers 從兩端交替取值

Approaches#

1: 排序 + 重新交錯放置#

  • 概念: 排序後,分成前半(小值)和後半(大值),交替插入新陣列
  • 時間複雜度: O(n log n) - 排序主導
  • 空間複雜度: O(n) - 結果陣列
class Solution {
    fun rearrangeArray(nums: IntArray): IntArray {
        nums.sort()
        val result = IntArray(nums.size)
        var left = 0
        var right = nums.size - 1
        var idx = 0
        while (idx < nums.size) {
            result[idx] = nums[left++]
            idx++
            if (idx < nums.size) {
                result[idx] = nums[right--]
                idx++
            }
        }
        return result
    }
}

⭐2: 排序 + Swap 成 Wiggle 排列#

  • 概念: 排序後,從 index 1 開始每隔一個做相鄰交換,保證偶數位 < 奇數位 > 偶數位
  • 時間複雜度: O(n log n) - 排序主導
  • 空間複雜度: O(1) - 原地操作(不計排序空間)
class Solution {
    fun rearrangeArray(nums: IntArray): IntArray {
        nums.sort()
        // 每次取兩個相鄰元素交換,使得排列呈鋸齒狀
        var i = 1
        while (i < nums.size - 1) {
            val temp = nums[i]
            nums[i] = nums[i + 1]
            nums[i + 1] = temp
            i += 2
        }
        return nums
    }
}

所有元素互不相同是此題的重要前提,否則 Wiggle Sort 不一定能保證嚴格不等。

🔑 Takeaways#

  • Pattern: Wiggle Sort / 鋸齒排列
  • 關鍵技巧: 排序後相鄰交換產生鋸齒效果;「不等於鄰居平均」等價於「嚴格大於或嚴格小於兩鄰居」