这一题我最初的想法是通过partitioning将数组分成大小两边,譬如,3,5,1,6,2,4可以变成3, 1, 2, 5, 6, 4。这个过程是可以通过partitioning和 selection ranking algorithm进行实现的。然后左右两边进行交换,左边的位置永远从index 1开始,右边的位置就根据数组的SIZE是奇数还是偶数决定。如果是偶数就是最后一个数字,但如果是奇数就是倒数第二个数字,然后左右交换,每交换一次,左边INDEX往右跳两个,右边INDEX往左跳两个。直到两边指针相遇为止。
public void swap(int[] nums, int a, int b) {
if (a != b) {
nums[a] ^= nums[b];
nums[b] ^= nums[a];
nums[a] ^= nums[b];
}
}
public int partition(int[] nums, int head, int tail) {
int pivot = nums[tail];
int j = head;
for (int i = head; i < tail; i++) {
if (nums[i] <= pivot) {
swap(nums, i, j);
j++;
}
}
swap(nums, tail, j);
return j;
}
public void partitionMid(int[] nums) {
int head = 0, tail = nums.length - 1;
int mid = nums.length / 2;
while (head <= tail) {
int k = partition(nums, head, tail);
if (k == mid) return;
else if (k > mid) tail = k - 1;
else head = k + 1;
}
}
public void wiggleSort(int[] nums) {
partitionMid(nums);
int left = 1, right = nums.length % 2 == 0 ? nums.length - 2 : nums.length - 1;
while (left < right) {
swap(nums, left, right);
left += 2;
right -= 2;
}
}
这个解法最坏情况O(N^2),平均是O(N)的,主要是partition带来的复杂度
这题其实还有一个更优解,也非常简单。只需要从左往右扫一次,如果当前INDEX是奇数,那么前面比它大的话就和前面那个数字交换,如果当前INDEX是偶数,那么前面比它小的话就进行交换。就是这么简单....
简单解释一下这种做法的原理的话就是这样的。假如我们有一个数组为arr。
如果arr[1]比arr[0]大的话就符合条件了,arr[1] < arr[0]的话那么arr[1]和arr[0]交换,变成了arr[1], arr[0]....,此时如果arr[2]比arr[0]大的话,就是arr[1] < arr[0] < arr[2]的话,我们再交换arr[0]和arr[2],这个时候arr[2]和arr[0]之间的条件达到了,但是这样主要的问题在于是否会破坏原来arr[1]和arr[0]构造好的关系。但因为arr[2] > arr[0] > arr[1],所以最后还会是arr[1] < arr[2] > arr[0]。往后延续下去也是一样的。根据这个算法,给出以下代码:
public void swap(int[] nums, int a, int b) {
if (a != b) {
nums[a] ^= nums[b];
nums[b] ^= nums[a];
nums[a] ^= nums[b];
}
}
public void wiggleSort(int[] nums) {
for (int i = 1; i < nums.length; ++i) {
if (i % 2 == 1 && nums[i] < nums[i - 1]) {
swap(nums, i, i - 1);
} else if (i % 2 == 0 && nums[i] > nums[i - 1]) {
swap(nums, i, i - 1);
}
}
}