Given an unsorted array nums
, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]...
.
Example 1:
Input:nums = [1, 5, 1, 1, 6, 4]
Output: One possible answer is[1, 4, 1, 5, 1, 6]
Example 2:
Input:nums = [1, 3, 2, 2, 3, 1]
Output: 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?
题目链接:https://leetcode.com/problems/wiggle-sort-ii/
题目分析:感觉follow up是可以归到hard一类的,discuss里发现的所有O(n)时间的解法无非两种
1. nth_element,它的作用是求第n大的元素,并把它放在第n位置上,做过kdtree的同学应该不陌生
2. 快速选择,基于快排的思想
可惜上面两种求取中位数的方式都不是严格意义上的O(n),下面说下我的做法
由于本题的输入均为32位整型,故可以通过二分的方式来求得中位数,目标是先找到一个最小的x使得小于等于它的数字个数大于等于n/2,然后再找原数组中大于等于且与x最接近的数,即为要求得的中位数,即便题目给出的数字范围更大,只要位数是确定的,复杂度都可看做nlog2(常数) => O(n)
求出中位数后不难想到按下标奇偶分开插数字,因为题目保证有解, 问题就变成了三部分的划分,大于中位数,小于中位数,等于中位数,类比经典的sort 3 colors问题,采用三分法,有一个贪心思想,即中位数尽可能分散,需对原下标做reindex(这里后来参考了StefanPochmann的解法,十分优美)。
题目应该是数据水了,下面的代码跑了7ms,然而最快的3ms代码尽然是时间nlogn,空间n的做法
class Solution {
public int n;
public void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public int getLess(int x, int[] nums) {
int lessNum = 0;
for (int i = 0; i < n; i++) {
if (nums[i] <= x) {
lessNum++;
}
}
return lessNum;
}
public int getMid(int[] nums, int ma, int mi) {
int l = mi, r = ma, mid = 0, ans = 0, lessNum = 0;
while (l <= r) {
mid = (l >> 1) + (r >> 1) + (l & r & 1);
lessNum = getLess(mid, nums);
if (lessNum <= (n >> 1)) {
l = mid + 1;
} else {
r = mid - 1;
ans = mid;
}
}
return ans;
}
public int vi(int x) {
return (x << 1 | 1) % (n | 1);
}
public void wiggleSort(int[] nums) {
n = nums.length;
int ma = nums[0], mi = nums[0];
for (int i = 0; i < n; i++) {
ma = Math.max(ma, nums[i]);
mi = Math.min(mi, nums[i]);
}
int tmid = getMid(nums, ma, mi);
int mid = nums[0], minDiff = ma - mi;
for (int i = 0; i < n; i++) {
if (nums[i] >= tmid && nums[i] - tmid < minDiff) {
minDiff = nums[i] - tmid;
mid = nums[i];
}
}
int l = 0, r = n - 1;
for (int i = 0; i <= r; i++) {
if (nums[vi(i)] > mid) {
swap(nums, vi(i), vi(l));
l++;
} else if (nums[vi(i)] < mid) {
swap(nums, vi(i), vi(r));
i--;
r--;
}
}
}
}