mirror of
https://github.com/ShusenTang/LeetCode.git
synced 2024-09-02 14:20:01 +00:00
123 lines
4.8 KiB
Markdown
123 lines
4.8 KiB
Markdown
![]() |
# [324. Wiggle Sort II](https://leetcode.com/problems/wiggle-sort-ii/)
|
|||
|
|
|||
|
# 思路
|
|||
|
题目给定一个无序数组,让我们排序成摆动数组,满足nums[0] < nums[1] > nums[2] < nums[3]...。
|
|||
|
|
|||
|
## 思路一
|
|||
|
我们可以先给数组排序,知道每个数的大小关系后就好按照题意进行调整了。
|
|||
|
我们从中间把有序数组从中间分成两部分:
|
|||
|
1. 前半部分S: nums[0,...,n/2);
|
|||
|
2. 后半部分B: nums[n/2,...,n-1]。
|
|||
|
|
|||
|
这样就保证了B段所有数都大于等于S段的所有数。然后从前半段S的末尾取一个,在从后段B的末尾去一个,这样保证了第一个数小于第二个数,然后从前半段取倒数第二个,从后半段取倒数第二个,这保证了第二个数大于第三个数,且第三个数小于第四个数,以此类推直至都取完。
|
|||
|
|
|||
|
> 需要注意的是,因为存在重复元素,所以我们需要把S中比较大的数和B中比较小的数放的越远越好。所以应该先取S中较大的数,最后取B中较小的数,即必须都从末尾开始取。
|
|||
|
比如当数组为[1,2,2,3]时,只有都从末尾取才能得到正确结果[2,3,1,2]。
|
|||
|
|
|||
|
|
|||
|
由于排序的时间复杂度为O(nlogn), 所以时间复杂度为O(nlogn)。最后交替取数的时候需要开辟一个数组备份排好序的nums,所以空间复杂度为O(n)。
|
|||
|
|
|||
|
## 思路二
|
|||
|
思路一排序的目的仅仅是等分成两段S和B使S中的元素都不大于B中的元素,那么我们完全没必要排序,只需要找到中位数然后根据中位数划分就行了。
|
|||
|
|
|||
|
1. 我们可以用O(n)的时间复杂度和O(1)空间复杂度查找数组中第k大的数,这就是第[215题](https://github.com/ShusenTang/LeetCode/blob/master/solutions/215.%20Kth%20Largest%20Element%20in%20an%20Array.md)干的事情,这里我们用STL中现成的函数`nth_element`:
|
|||
|
``` C++
|
|||
|
nth_element(vc.begin(), vc.begin()+k, vc.end()); // 保证第 k 小的元素在第k个位置(返回空!)
|
|||
|
```
|
|||
|
2. 找到中位数后,需要将数组划分为三段依次为:大于中位数(L)、等于中位数(M)和小于中位数(S),即荷兰国旗问题,即[75题](https://github.com/ShusenTang/LeetCode/blob/master/solutions/75.%20Sort%20Colors.md)干的事情,采用快排划分的思想,时间复杂度O(n),空间复杂度O(1)。
|
|||
|
|
|||
|
然后就可以按照思路一的交替取值思想获得最终结果了。时间复杂度为O(n),由于还是要交替取数,所以需要开辟备份数组,空间复杂度为O(n)。
|
|||
|
|
|||
|
## 思路二空间改进版
|
|||
|
思路二最后的交替取值实际上是将索引重新映射的过程,而且这个映射是固定的。举两个例子
|
|||
|
```
|
|||
|
例 1
|
|||
|
n = 5
|
|||
|
索引: 0 1 2 3 4
|
|||
|
交替取值后的索引: 4 2 0 3 1
|
|||
|
|
|||
|
例 2
|
|||
|
n = 6
|
|||
|
索引: 0 1 2 3 4 5
|
|||
|
交替取值后的索引: 4 2 0 5 3 1
|
|||
|
```
|
|||
|
仔细观察可得出这个固定的映射是`func(i) = (2*n - 2*i - 1) % (n | 1)`,所以我们可以在划分的时候就进行这个映射,这样就不用最后再进行交替取值,空间优化到O(1)。
|
|||
|
|
|||
|
|
|||
|
# C++
|
|||
|
## 思路一
|
|||
|
``` C++
|
|||
|
class Solution {
|
|||
|
public:
|
|||
|
void wiggleSort(vector<int>& nums) {
|
|||
|
vector<int>tmp = nums;
|
|||
|
sort(tmp.begin(), tmp.end());
|
|||
|
|
|||
|
int n = nums.size();
|
|||
|
int p1 = (n - 1) / 2, p2 = n - 1;
|
|||
|
|
|||
|
for(int i = 0; i < n; i++){
|
|||
|
if(i & 1) nums[i] = tmp[p2--];
|
|||
|
else nums[i] = tmp[p1--];
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
## 思路二
|
|||
|
``` C++
|
|||
|
class Solution {
|
|||
|
public:
|
|||
|
void wiggleSort(vector<int>& nums) {
|
|||
|
int n = nums.size();
|
|||
|
auto mid_ptr = nums.begin() + n / 2;
|
|||
|
nth_element(nums.begin(), mid_ptr, nums.end());
|
|||
|
int mid = *mid_ptr;
|
|||
|
|
|||
|
// [0,small_right)全部小于mid
|
|||
|
// (big_left, n-1]全部大于mid
|
|||
|
int small_right = 0, big_left = n - 1;
|
|||
|
int i = 0;
|
|||
|
|
|||
|
while(i <= big_left){
|
|||
|
if(nums[i] < mid)
|
|||
|
swap(nums[small_right++], nums[i++]);
|
|||
|
else if(nums[i] == mid) i++;
|
|||
|
else swap(nums[big_left--], nums[i]); // 这里不更新i!!!
|
|||
|
}
|
|||
|
|
|||
|
vector<int>tmp = nums;
|
|||
|
int p1 = (n - 1) / 2, p2 = n - 1;
|
|||
|
for(int i = 0; i < n; i++){
|
|||
|
if(i & 1) nums[i] = tmp[p2--];
|
|||
|
else nums[i] = tmp[p1--];
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
## 思路二空间优化
|
|||
|
``` C++
|
|||
|
class Solution {
|
|||
|
public:
|
|||
|
void wiggleSort(vector<int>& nums) {
|
|||
|
int n = nums.size();
|
|||
|
auto mid_ptr = nums.begin() + n / 2;
|
|||
|
nth_element(nums.begin(), mid_ptr, nums.end());
|
|||
|
int mid = *mid_ptr;
|
|||
|
|
|||
|
int small_right = 0, big_left = n - 1;
|
|||
|
int i = 0;
|
|||
|
|
|||
|
#define A(i) nums[(2*n - 2*i - 1) % (n | 1)]
|
|||
|
|
|||
|
while(i <= big_left){
|
|||
|
if(A(i) < mid)
|
|||
|
swap(A(small_right++), A(i++));
|
|||
|
else if(A(i) == mid) i++;
|
|||
|
else swap(A(big_left--), A(i)); // 这里不更新i!!!
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
```
|