题目:给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。
说明: 你可以假设所有输入都会得到有效的结果。
输入: nums = [1, 5, 1, 1, 6, 4]
输出: 一个可能的答案是 [1, 4, 1, 5, 1, 6]
原理:
首先,我们可以很容易想到一种简单的解法:将数组进行排序,
然后从中间位置进行等分(如果数组长度为奇数,则将中间的元素分到前面),
然后将两个数组进行穿插。
例如:对于数组[1, 5, 2, 4, 3],我们将其排序,得到[1, 2, 3, 4, 5],
然后将其分割为[1, 2, 3]和[4, 5],对两个数组进行穿插,得到[1, 4, 2, 5, 3]。
但是这一解法有一个问题,例如,对于数组[1, 2, 2, 3],按照这种做法求得的结果仍为[1, 2, 2, 3]。
如果题目不要求各元素严格大于或小于相邻元素,那么这一解法是符合要求的,
但题目要求元素相互严格大于或小于
在下文中定义前半部分为数组A,后半部分数组B。
显然,出现上述现象是因为nums中存在重复元素。实际上,由于穿插之后,相邻元素必来自不同子数组,
所以,出现上述情况其实是因为数组A和数组B出现了相同元素,我们用r来表示这一元素。
而且我们可以很容易发现,如果A和B都存在r,那么r一定是A的最大值,B的最小值,
这意味着r一定出现在A的尾部,B的头部。
要解决这一问题,我们需要使A的r和B的r在穿插后尽可能分开。一种可行的办法是将A和B反序:
例如,对于数组[1,1,2,2,2,3],分割为[1,1,2]和[2,2,3],分别反序后得到[2, 1, 1]和[3, 2, 2],
此时2在A头部,B尾部,穿插后就不会发生相邻了。
由于需要使用排序,时间复杂度为O(NlogN),由于需要存储A和B,所以空间复杂度为O(N)。
流程:
1. 把原数组nums排序
2. 从左到右遍历 拷贝数组copy 的奇数位置, 从右往左把nums的值依次放入奇数位置
3. 把nums剩下的 还是从右往左 放入 copy数组从左往右的偶数位置
public void wiggleSort(int[] nums) {
Arrays.sort(nums);
if (nums.length <= 2) return;
int[] copy = new int[nums.length];
int mid = nums.length >> 1;
int index = nums.length - 1;
for (int odd = 1; odd < copy.length; odd += 2)
copy[odd] = nums[index--];
for (int even = 0; even < copy.length; even += 2)
copy[even] = nums[index--];
index = 0;
for (int num : copy) nums[index++] = num;
}
方法2. 时间空间优化 没有做