動機
神奇的indexing
Problem
Given an integer array nums
, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]...
.
You may assume the input array always has a valid answer.
Example 1:
Input: nums = [1,5,1,1,6,4]Output: [1,6,1,5,1,4]Explanation: [1,4,1,5,1,6] is also accepted.
Example 2:
Input: nums = [1,3,2,2,3,1]Output: [2,3,1,3,1,2]
Constraints:
1 <= nums.length <= 5 * 104
0 <= nums[i] <= 5000
- It is guaranteed that there will be an answer for the given input
nums
.
Follow Up: Can you do it in
O(n)
time and/or in-place with O(1)
extra space?Sol
每次遇到整數除法都很頭痛,如果沒有處理好就是錯
排序後折半,從最後去塞
這裡要讓小的部分多拿一點,看奇數長度的例子,就會發現小的一定在最後一個
class Solution:
def wiggleSort(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
tmp = [x for x in nums]
tmp.sort()
a = (len(nums)//2 if len(nums) % 2 == 0 else (len(nums)+1)//2)-1
# a = ((len(nums)+1)//2)-1
b = len(nums)-1
for i in range(len(nums)):
if i % 2 == 0:
nums[i] = tmp[a]
a -= 1
else:
nums[i] = tmp[b]
b -= 1
Case study
第一個是用nth_element把array分成左右兩邊
第二個用A(i)把
- A的前半對應到nums上應該放大數字的部分
- A的後半對應到nums上應該放小數字的部分
Accessing A(0) actually accesses nums[1].
Accessing A(1) actually accesses nums[3].
Accessing A(2) actually accesses nums[5].
Accessing A(3) actually accesses nums[7].
Accessing A(4) actually accesses nums[9].
Accessing A(5) actually accesses nums[0].
Accessing A(6) actually accesses nums[2].
Accessing A(7) actually accesses nums[4].
Accessing A(8) actually accesses nums[6].
Accessing A(9) actually accesses nums[8].
從上面可以看出,在替A(i)切半時應該把前半的長度壓小一點,理由在Sol,所以這邊mid就是直接除2就好
void wiggleSort(vector<int>& nums) {
int n = nums.size();
// Find a median.
auto midptr = nums.begin() + n / 2;
nth_element(nums.begin(), midptr, nums.end());
int mid = *midptr;
// Index-rewiring.
#define A(i) nums[(1+2*(i)) % (n|1)]
// j :: iterate through A()
int i = 0, j = 0, k = n - 1;
while (j <= k) {
if (A(j) > mid)
swap(A(i++), A(j++)); // expand 大數字的範圍
else if (A(j) < mid)
swap(A(j), A(k--)); // expand 小數字的範圍
else
j++;
}
}