Description
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.
Solution
比较难的一道题,因为数组中可能会有重复元素,不考虑重复元素的话会造成nums[i] == nums[i + 1]这种情况,是不合要求的。
Quick select + Sort colors, time O(n), space O(1)
- 使用O(n)时间复杂度的quickSelect算法,从未经排序的数组nums中选出中位数mid
- 参照解法I的思路,将nums数组的下标x通过函数idx()从[0, 1, 2, ... , n - 1, n] 映射到 [1, 3, 5, ... , 0, 2, 4, ...],得到新下标ix
- 以中位数mid为界,将大于mid的元素排列在ix的较小部分,而将小于mid的元素排列在ix的较大部分。
详见:https://leetcode.com/discuss/77133/o-n-o-1-after-median-virtual-indexing
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 newIndex(int index, int n) {
return (1 + 2*index) % (n | 1);
}
public int findKthLargest(int[] nums, int k) {
return findKthLargest(nums, 0, nums.length - 1, k);
}
private int findKthLargest(int[] nums, int l, int r, int k) {
int index = partition(nums, l, r);
if (index == nums.length - k) {
return nums[index];
} else if (index < nums.length - k) {
return findKthLargest(nums, index + 1, r, k);
} else {
return findKthLargest(nums, l, index - 1, k);
}
}
private int partition(int[] nums, int l, int r) {
int pivot = nums[r];
int i = l;
while (l < r) {
if (nums[l] <= pivot) {
swap(nums, l, i++);
}
++l;
}
swap(nums, r, i);
return i;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}