280. Wiggle Sort
MediumDescription
給定未排序的陣列
nums,原地重排使得nums[0] <= nums[1] >= nums[2] <= nums[3] ...(交替的小於等於和大於等於)。
Example:
Input: nums = [3,5,2,1,6,4] Output: [3,5,1,6,2,4](任何滿足 wiggle 條件的排列皆可)
Intuition#
核心思路:一次遍歷,若 index 為奇數時
nums[i] < nums[i-1],或 index 為偶數時nums[i] > nums[i-1],就交換相鄰兩元素。
- 奇數位應該是局部最大(
nums[i] >= nums[i-1]) - 偶數位應該是局部最小(
nums[i] <= nums[i-1]) - 若不滿足就交換,交換不會破壞前面的 wiggle 性質
Approaches#
1: Sort Then Swap#
- 概念: 先排序,然後每兩個元素一組交換(swap
nums[1]和nums[2],swapnums[3]和nums[4]…) - 時間複雜度:
O(n log n)- 排序主導 - 空間複雜度:
O(1)- 原地排序後原地交換
class Solution {
fun wiggleSort(nums: IntArray) {
nums.sort()
for (i in 1 until nums.size - 1 step 2) {
val temp = nums[i]
nums[i] = nums[i + 1]
nums[i + 1] = temp
}
}
}⭐2: One-Pass Greedy Swap#
- 概念: 遍歷陣列,根據當前 index 的奇偶性判斷是否需要交換相鄰元素
- 時間複雜度:
O(n)- 一次遍歷 - 空間複雜度:
O(1)- 原地操作
class Solution {
fun wiggleSort(nums: IntArray) {
for (i in 1 until nums.size) {
if ((i % 2 == 1 && nums[i] < nums[i - 1]) ||
(i % 2 == 0 && nums[i] > nums[i - 1])) {
val temp = nums[i]
nums[i] = nums[i - 1]
nums[i - 1] = temp
}
}
}
}為什麼交換不會破壞前面已建立的 wiggle 性質?以奇數位為例:若
nums[i] < nums[i-1],交換後nums[i-1]變更小,而偶數位i-1本就要求較小值,所以i-2到i-1的關係不會被破壞。
🔑 Takeaways#
- Pattern: Wiggle / 交替排序 -> 局部性質的 Greedy 交換
- 關鍵技巧: 只看相鄰兩元素的局部關係,O(n) 一次遍歷解決問題。注意 Wiggle Sort II(324 題)要求嚴格不等式,解法不同且更難