Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3].... Example: (1) Given nums = [1, 5, 1, 1, 6, 4], one possible answer is [1, 4, 1, 5, 1, 6]. (2) Given nums = [1, 3, 2, 2, 3, 1], one possible answer is [2, 3, 1, 3, 1, 2]. Note: You may assume all input has valid answer. Follow Up: Can you do it in O(n) time and/or in-place with O(1) extra space? Credits: Special thanks to @dietpepsi for adding this problem and creating all test cases.
Let's say nums
is [10,11,...,19]
. Then after nth_element and ordinary partitioning, we might have this (15 is my median):
index: 0 1 2 3 4 5 6 7 8 9
number: 18 17 19 16 15 11 14 10 13 12
I rewire it so that the first spot has index 5, the second spot has index 0, etc, so that I might get this instead:
index: 5 0 6 1 7 2 8 3 9 4
number: 11 18 14 17 10 19 13 16 12 15
And 11 18 14 17 10 19 13 16 12 15 is perfectly wiggly. And the whole partitioning-to-wiggly-arrangement (everything after finding the median) only takes O(n) time and O(1) space.
If the above description is unclear, maybe this explicit listing helps:
Accessing A(0)
actually accesses nums[1]
.
Accessing A(1)
actually accesses nums[3]
.
Accessing A(2)
actually accesses nums[5]
.
Accessing A(3)
actually accesses nums[7]
.
Accessing A(4)
actually accesses nums[9]
.
Accessing A(5)
actually accesses nums[0]
.
Accessing A(6)
actually accesses nums[2]
.
Accessing A(7)
actually accesses nums[4]
.
Accessing A(8)
actually accesses nums[6]
.
Accessing A(9)
actually accesses nums[8]
.
不需要排序,只需要 partitioning. 正确 partition 的数组只
要按照这个顺序插入,都是正确的。
于是问题就分成了三个子问题:
怎么 partitioning
什么顺序穿插
如何 in-place
空间优化:
public void wiggleSort(int[] nums) { int median = findKthLargest(nums, (nums.length + 1) / 2); int n = nums.length; int left = 0, i = 0, right = n - 1; while (i <= right) { if (nums[newIndex(i,n)] > median) { swap(nums, newIndex(left++,n), newIndex(i++,n)); } else if (nums[newIndex(i,n)] < median) { swap(nums, newIndex(right--,n), newIndex(i,n)); } else { i++; } } } private int newIndex(int index, int n) { return (1 + 2*index) % (n | 1); }
O(n) O(n)
public class Solution { public void wiggleSort(int[] nums) { int median = findKthLargest(nums, (nums.length+1)/2); int odd = 1, even = (nums.length%2==0? nums.length-2 : nums.length-1); int[] arr = new int[nums.length]; for (int num : nums) { if (num > median) { arr[odd] = num; odd += 2; } else if (num < median) { arr[even] = num; even -= 2; } } while (odd < arr.length) { arr[odd] = median; odd += 2; } while (even >= 0) { arr[even] = median; even -= 2; } for (int i=0; i<arr.length; i++) { nums[i] = arr[i]; } } public int findKthLargest(int[] nums, int k) { int len = nums.length; return findKthSmallest(nums, 0, len-1, len-k+1); } public int findKthSmallest(int[] nums, int start, int end, int k) { int l = start; int r = end; int pivot = end; while (l < r) { while (l<r && nums[l] < nums[pivot]) { l++; } while (l<r && nums[r] >= nums[pivot]) { r--; } if (l == r) break; swap(nums, l, r); } swap(nums, l, pivot); if (l+1 == k) return nums[l]; else if (l+1 < k) return findKthSmallest(nums, l+1, end, k); else return findKthSmallest(nums, start, l-1, k); } public void swap(int[] nums, int l, int r) { int temp = nums[l]; nums[l] = nums[r]; nums[r] = temp; } }
A(i) = nums[(1+2*(i)) % (n|1)] -----------(n|1) 强行变奇数