分析: 题意很简单,让偶数位的数字大于其左右两边的数字,但是有一个要求就是 时间复杂度为O(n) 空间复杂度为O(1)。 这意味这我们必须使用一个原地算法。 同时想要使他们有序,最简单的办法就是让他们的奇数位上的数是前一半的数字,偶数位上的数字为后一半的数字。
这时候的第一反应就是快速排序,我们知道,快速排序的核心思想就是把一个数组分为两半一半小于一个数,另一半大于一个数,然后继续递归去求解,
所以我的思路是:
a. 找到数组正中间的元素
b. 从这个元素开始(包括这个元素)以及比它大的元素,统统放到偶数位。之前的元素统一放到奇数位
c. 这时候有一个问题,就是多个中位数时,可能会碰面,所以调整数组,把中位数一个从开头开始放,一个从结尾开始放。
a. 找到数组正中间的元素(即求解中位数)
线复习一下快速排序,我喜欢用的方法就是填坑法,
step1,选择第一个元素,拿出它的值,它现在的位置就是一个坑
step2,开始迭代找到该值的位置
step3,开始从该该值的前一个位置和后一个位置重新迭代
void quickSort(vector<int>& nums, int begin, int end){
if(begin >= end) return;
int x = nums[begin]; //step1 选择第一个元素,拿出它的值,它现在的位置就是一个坑
int i = begin, j = end;
while(i < j){ //step2 开始迭代找到该值的位置
while(i < j && nums[j] >= x) --j;
if(i < j){//填坑,现在的坑成了j的位置
int temp = nums[i]; nums[i++] = nums[j]; nums[j] = temp;
}
while(i < j && nums[i] <= x) ++i;
if(i < j){//填坑,现在的坑成了i的位置
int temp = nums[j]; nums[j--] = nums[i]; nums[i] = temp;
}
}
nums[i] = x;
quickSort(nums, begin, i -1); //递归排序
quickSort(nums, i + 1, end);
}
我们怎么把快排分治的思想,用到这道题目呢?
即用快排的思想取中位数,想法很简单
a 用第一个数进行迭代找到它的位置,设为x 对应上面代码的i
b 如果x 小于mid,那么下一次迭代就是x to end
c 如果x 大于mid,那么下一次的迭代就是begin to x
int search(vector<int>& nums, int l, int r){
int x = nums[l];
while(r > l){
while(r > l && nums[r] >= x)
r--;
if(r > l) nums[l++] = nums[r];
while(r > l && nums[l] <= x)
l++;
if(r > l) nums[r--] = nums[l];
}
nums[l] = x;
return l;
}
int findMidNum(vector<int>& nums, int mid){
int l = 0, r = nums.size() - 1;
int j = search(nums, l, r);
while(r > l){
if (j == mid) break;
if(j > mid)
r = j-1;
else
l = j+1;
j = search(nums, l, r);
}
return nums[mid];
}
search函数就是找当前第一个数在数组中的位置,理论上这个办法找到中位数的时间O(n)
b. 从这个元素开始(包括这个元素)以及比它大的元素,统统放到偶数位。之前的元素统一放到奇数位
p:第一个后半部分数的值的位置,每次+2
q: 后边部分数现在的位置
count: 记录后半部分有几个中位数
p是追不上q的
假设小明和小红相距x m,小明以 1 m/s 的速度前进 小红以 2 m/s 的速度前进
小红追上小明需要 比小明多走 x m,这时候就到数组最后了
int p = 1, q = mid + 1, count = 0;
while(q < nums.size()){
if(nums[q] == midNum) count++;
int temp = nums[q]; nums[q] = nums[p]; nums[p] = temp;
p = p + 2; q++;
}
c. 这时候有一个问题,就是多个中位数时,可能会碰面,所以调整数组,把中位数一个从开头开始放,一个从结尾开始放。
l ,r : 对应后面调整的标志位
//left
int l = 0; p = 2;
while(p < nums.size()){
if(nums[p] == midNum){
//exchage
int temp = nums[p]; nums[p] = nums[l]; nums[l] = temp;
l = l + 2;
}
p = p + 2;
}
int r = nums.size() % 2 == 0 ? nums.size() - 1 : nums.size() - 2; q = r;
while(q > 0){
if(nums[q] == midNum){
//exchange
int temp = nums[q]; nums[q] = nums[r]; nums[r] = temp;
r = r - 2;
}
q = q - 2;
}
最后附上最终的code
int search(vector<int>& nums, int l, int r){
int x = nums[l];
while(r > l){
while(r > l && nums[r] >= x)
r--;
if(r > l) nums[l++] = nums[r];
while(r > l && nums[l] <= x)
l++;
if(r > l) nums[r--] = nums[l];
}
nums[l] = x;
return l;
}
int findMidNum(vector<int>& nums, int mid){
int l = 0, r = nums.size() - 1;
int j = search(nums, l, r);
while(r > l){
if (j == mid) break;
if(j > mid)
r = j-1;
else
l = j+1;
j = search(nums, l, r);
}
return nums[mid];
}
void wiggleSort(vector<int>& nums) {
if(nums.size() <= 1) return;
int mid = 0 + (nums.size() - 1) / 2;
int midNum = findMidNum(nums, mid);
int p = 1, q = mid + 1, count = 0;
while(q < nums.size()){
if(nums[q] == midNum) count++;
int temp = nums[q]; nums[q] = nums[p]; nums[p] = temp;
p = p + 2; q++;
}
if(count == 0) return;
//left
int l = 0; p = 2;
while(p < nums.size()){
if(nums[p] == midNum){
//exchage
int temp = nums[p]; nums[p] = nums[l]; nums[l] = temp;
l = l + 2;
}
p = p + 2;
}
int r = nums.size() % 2 == 0 ? nums.size() - 1 : nums.size() - 2; q = r;
while(q > 0){
if(nums[q] == midNum){
//exchange
int temp = nums[q]; nums[q] = nums[r]; nums[r] = temp;
r = r - 2;
}
q = q - 2;
}
}