Wiggle Sort II
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.
Tips:
average O(n) time and O(1) space.
Assume your original array is {6,13,5,4,5,2}. After you get median element, the 'nums' is partially sorted such that the first half is larger or equal to the median, the second half is smaller or equal to the median, i.e
13 6 5 5 4 2
M
to get wiggle sort, you want to put the number in the following way such that
(1) elements smaller than the 'median' are put into the last even slots
(2) elements larger than the 'median' are put into the first odd slots
(3) the medians are put into the remaining slots.
Index : 0 1 2 3 4 5
Small half: M S S
Large half: L L M
M - Median, S-Small, L-Large. In this example, we want to put {13, 6, 5} in index 1,3,5 and {5,4,2} in index {0,2,4}
The index mapping, (1 + 2*index) % (n | 1)(这个是位运算里的或) combined with 'Color sort', will do the job.
After selecting the median element, which is 5 in this example, we continue as the following
Mapped_idx[Left] denotes the position where the next smaller-than median element will be inserted.
Mapped_idx[Right] denotes the position where the next larger-than median element will be inserted.
Step 1:
Original idx: 0 1 2 3 4 5
Mapped idx: 1 3 5 0 2 4
Array: 13 6 5 5 4 2
Left
i
Right
nums[Mapped_idx[i]] = nums[1] = 6 > 5, so it is ok to put 6 in the first odd index 1. We increment i and left.
Step 2:
Original idx: 0 1 2 3 4 5
Mapped idx: 1 3 5 0 2 4
Array: 13 6 5 5 4 2
Left
i
Right
nums[3] = 5 = 5, so it is ok to put 6 in the index 3. We increment i.
Step 3:
Original idx: 0 1 2 3 4 5
Mapped idx: 1 3 5 0 2 4
Array: 13 6 5 5 4 2
Left
i
Right
nums[5] = 2 < 5, so we want to put it to the last even index 4 (pointed by Right). So, we swap nums[Mapped_idx[i]] with nums[Mapped_idx[Right]], i.e. nums[5] with nums[4], and decrement Right.
Code:
public class Solution {
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 findKthLargest(int[] nums, int k) {
k = nums.length - k;
int lo = 0;
int hi = nums.length - 1;
while (lo < hi) {
final int j = partition(nums, lo, hi);
if(j < k) {
lo = j + 1;
} else if (j > k) {
hi = j - 1;
} else {
break;
}
}
return nums[k];
}
private int partition(int[] nums, int left, int right) {
int i = left;
int j = right + 1;
while(true) {
while(i < right && nums[++i] < nums[left]);
while(j > left && nums[left] < nums[--j]);
if(i >= j) {
break;
}
swap(nums, i, j);
}
swap(nums, left, j);
return j;
}
private int newIndex(int index, int n) {
return (1 + 2*index) % (n | 1);
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}