324 Wiggle Sort II
Note the corner case:
[1,1,1,2,2,3,3]
[1,1,2,2,3,3]
[1,1,1,2,2,2]
[1,1,1,1,2,2,2]
[1,1,1,2,2,2,2]
[4,5,5,6]
思路
这题好抓狂啊,看着很简单,但好多corner case;一定是我打开方式不对...所以用中文写来理理思路。
什么情况不能摇摆排序?
感觉有很多漏洞,再想一下
假设我们已经把数组排序好了:
$$a_1 \leq a_2 \leq ...... \leq a_l <mid_1 = mid_2 = ...... = mid_m < b_1 \leq b_2 ...... \leq b_g$$
先考虑一个偶数情形:$$l+m+g = 2N$$。
摇摆排序就是把后半段数组($$n{(N+1) \sim 2N}$$)嵌套到前半段数组($$n{1 \sim N}$$)中。具体有两种嵌套方式:
(1) $$n1, n{N+1}, n2, n{N+2}......nN, n{2N}$$
(2) $$nN, n{2N}, n{N-1}, n{2N-1}......n1, n{N+1}$$
有一种感觉,当中位数很多的时候不能排序。
偶数(2N)情况
当 m == N 时
example 1: [2, 2, 2, 3, 3, 3] :)
example 2: [1, 2, 2, 2, 3, 3]
Method 1 :(
first half: 1, 2, 2
second half: 2, 3, 3
Method 2 :)
first reversed half: 2, 2, 1
second reversed half: 3, 3, 2
example 3: [1, 1, 2, 2, 2, 3]
Method 1 :(
first half: 1, 1, 2
second half: 2, 2, 3
Method 2 :)
first reversed half: 2, 1, 1
second reversed half: 3, 2, 2
当 m == N+1 时
example 1: [1, 2, 2, 2, 2, 3] :(
example 2: [1, 1, 1, 1, 2, 2] :(
奇数(2N+1)情况:
当 m == N 时
example 1: [1, 1, 2, 2, 4] :)
first reversed half: 2, 1, 1
second reversed half: 4, 2
example 2: [1, 2, 2, 3, 3] :)
first reversed half: 2, 2, 1
second reversed half: 3, 3
当 m == N+1 时
example 1: [1, 2, 2, 2, 3] :(
example 2: [1, 1, 2, 2, 2] :(
example 3: [2, 2, 2, 3, 3] :)
所以对于长度为$$2N+1$$的数组,摇摆排序存在的条件是 $$m \leq N$$。
- 综上所述,一个数组能形成摇摆排序的条件是:中位数个数$$m$$满足:$$m \leq \frac{n}{2}$$, 其中$$n$$为数组长度。
算法。
- 最简单的就是排序,然后用倒序的两段数组相互嵌套得到结果(Solution 1);
- 为了避免排序带来的$$O(NlogN)$$的时间复杂度,我们可以采用 3-way quick select的算法将数组分成三段,严格比中位数小的, 等于中位数的,以及严格比中位数大的(Solution 2)。
- 上述两种解法都需要一个额外数组进行排序,如何利用$$O(1)$$空间复杂度进行嵌套的操作(还没想出来)?
Solution 1
class Solution {
public:
void wiggleSort(vector<int>& nums) {
vector<int> help = nums;
sort(help.begin(), help.end());
int n = nums.size();
int j = n-1;
for ( int i = 1; i <= n-1; i += 2 ) nums[i] = help[j--];
for ( int i = 0; i <= n-1; i += 2 ) nums[i] = help[j--];
return;
}
};
Solution 2
class Solution {
public:
void quickSort(vector<int>&nums, int start, int end, int mid) {
int pivot = nums[start];
int i = start+1, j = end, k = start+1;
while ( k <= j ) {
if ( nums[k] == pivot ) { k += 1; continue;}
if ( nums[k] > pivot ) { swap(nums[k], nums[j--]); continue;}
if ( nums[k] < pivot and k == i ) { k++; i++; continue;}
if ( nums[k] < pivot and k != i ) { swap(nums[k], nums[i++]); continue;}
}
swap(nums[start], nums[i-1]);
if ( mid >= i-1 and mid <= j ) return;
if ( mid < i-1 ) quickSort(nums, start, i-2, mid);
if ( mid > j ) quickSort(nums, j+1, end, mid);
return;
}
void wiggleSort(vector<int>& nums) {
vector<int> help = nums;
int n = nums.size();
quickSort(help, 0, n-1, (n-1)/2);
int j = n-1;
for ( int i = 1; i <= n-1; i += 2 ) nums[i] = help[j--];
for ( int i = 0; i <= n-1; i += 2 ) nums[i] = help[j--];
return;
}
};
Notes
关于three-way quick sort:
http://www.geeksforgeeks.org/3-way-quicksort/