题干信息
- 这道题很容易想到利用排序来实现
- 将nums数组前后半部分分开,将后半部分插入前半部分两两之间即可。直观上感觉这样做是对的。实际上有问题!
- 考虑当nums为[4,5,5,2]时,按上面的做法得出的结果和nums原本是一致的。而实际上nums可以按照题意变为[4,5,2,5]
IDEA1:考虑逆序插入+分类讨论
当nums.length为偶数时,考虑将Nums首先从小到大进行排序,再将nums分成大小相同的两部分。设nums.length = n,则将nums分为的第一部分为
n
u
m
s
[
0
]
,
n
u
m
s
[
1
]
,
⋯
n
u
m
s
[
n
/
2
−
1
]
nums[0],nums[1],\cdots nums[n/2 -1]
nums[0],nums[1],⋯nums[n/2−1]
将nums分为的第二部分为:
n
u
m
s
[
n
/
2
]
,
n
u
m
s
[
n
/
2
+
1
]
,
⋯
n
u
m
s
[
n
−
1
]
nums[n/2],nums[n/2+1],\cdots nums[n-1]
nums[n/2],nums[n/2+1],⋯nums[n−1]
容易看出两者的长度是相同的。
- 如果 n u m s [ n / 2 ] > n u m s [ n / 2 − 1 ] nums[n/2]>nums[n/2-1] nums[n/2]>nums[n/2−1]时,我们可以放心的将后一个序列插入前一个序列之间,亦即最终构成序列 n u m s [ 0 ] , n u m s [ n / 2 ] , n u m s [ 1 ] , n u m s [ n / 2 + 1 ] ⋯ n u m s [ n − 1 ] , n u m s [ n / 2 − 1 ] nums[0],nums[n/2],nums[1],nums[n/2+1]\cdots nums[n-1],nums[n/2-1] nums[0],nums[n/2],nums[1],nums[n/2+1]⋯nums[n−1],nums[n/2−1]
- 但不能排除:
n
u
m
s
[
n
/
2
]
=
n
u
m
s
[
n
/
2
−
1
]
nums[n/2]=nums[n/2-1]
nums[n/2]=nums[n/2−1]的情况!
- 如果按照上述思路的话 [ 4 , 5 , 5 , 2 ] [4,5,5,2] [4,5,5,2]的例子就不行!
- 逆序插入可以很好的解决这一问题。将前一个序列逆序,后一个序列逆序。即最终构成的结果为
n u m s [ n / 2 − 1 ] , n u m s [ n − 1 ] , n u m s [ n / 2 − 2 ] , n u m s [ n − 2 ] , ⋯ n u m s [ 0 ] , n u m s [ n / 2 ] nums[n/2-1],nums[n-1],nums[n/2-2],nums[n-2],\cdots nums[0],nums[n/2] nums[n/2−1],nums[n−1],nums[n/2−2],nums[n−2],⋯nums[0],nums[n/2]
下面证明为什么上述逆序插入的思路是可行的。显然当 n u m s [ n / 2 ] > n u m s [ n / 2 − 1 ] nums[n/2]>nums[n/2-1] nums[n/2]>nums[n/2−1]时逆序插入的思路是可行的。只证明当 n u m s [ n / 2 ] = n u m s [ n / 2 − 1 ] nums[n/2]=nums[n/2-1] nums[n/2]=nums[n/2−1]上述思路是可行的。
- 首先,我们一定有 n u m s [ n / 2 − 1 ] < n u m s [ n − 1 ] nums[n/2-1]<nums[n-1] nums[n/2−1]<nums[n−1].若不然则 n u m s [ n / 2 − 1 ] = n u m s [ n − 1 ] nums[n/2-1]=nums[n-1] nums[n/2−1]=nums[n−1],则由于nums是经过排序的,至少一定有 n u m s [ n − 1 ] = n u m s [ n − 2 ] = ⋯ = n u m s [ n / 2 − 1 ] nums[n-1] = nums[n-2] = \cdots = nums[n/2 - 1] nums[n−1]=nums[n−2]=⋯=nums[n/2−1].这其中的数一共有: n − n / 2 + 1 = n / 2 + 1 n-n/2+1 = n/2+1 n−n/2+1=n/2+1个数,即相等的数比nums总长度的一半还多。因此无论如何怎样排列总有两个相同的数连在一起,不可能实现本题目所示的结果,这和题目的前提矛盾!
- 类似可以证明 n u m s [ n / 2 − 2 ] < n u m s [ n − 2 ] nums[n/2-2]<nums[n-2] nums[n/2−2]<nums[n−2]一直到 n u m s [ 0 ] < n u m s [ n / 2 ] nums[0] < nums[n/2] nums[0]<nums[n/2]
奇数情况可以类似证明。
下面的AC代码将奇数情况和偶数情况合并了。是高级语言中整除运算符的特性(向下取整)。
public void wiggleSort(int[] nums) {
int[] temp = nums.clone();
Arrays.sort(temp);
for(int i = 0;i<nums.length;i+=2)
{ //这里的(nums.length - 1)/2实际上是将两种情况都合并了!!
nums[i] = temp[(nums.length - 1)/2 - i/2];
}
for(int i = 1;i<nums.length;i+=2)
{
nums[i] = temp[nums.length - 1 - i / 2];
}
}
IDEA2:优化1-桶排序
根据题目所示的条件:0 <= nums[i] <= 5000。可以考虑使用桶排序,复杂度为 O ( n ) O(n) O(n)