LeetCode 324. Wiggle Sort II
Problem Description
Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]….
Example:
(1) Given nums = [1, 5, 1, 1, 6, 4], one possible answer is [1, 4, 1, 5, 1, 6].
(2) Given nums = [1, 3, 2, 2, 3, 1], one possible answer is [2, 3, 1, 3, 1, 2].
Note:
You may assume all input has valid answer.
Follow Up:
Can you do it in O(n) time and/or in-place with O(1) extra space?
Solution
這個題目看似簡單,實際上是比較難的。
一開始的想法是找到陣列的中位數,然後根據中位數對陣列劃分為兩部分。大的那一部分放在索引為奇數的位置(1,3,5,7,9…),小的那一部分放在索引為偶數的位置(0,2,4,6,8…)。(這裡是可以隨意放的)
這個想法是對的,但還不夠。比如當陣列為[4,5,5,6]時,得到的結果就是[4,5,5,6],這不符合題目要求,正確的結果應該是[5,6,4,5]。這裡問題出在兩部分數中相同大小的數放在一起了。
為了避免這個問題,直觀上來說,需要把較小的那一部分中比較大的數和較大的那一部分中比較小的數放的越遠越好。(要做到這樣有點難,因為這樣需要兩部分的數都有序,實際上一步劃分之後兩部分的數是無序的)
當然還一個簡單的方法,那就是確保和中位數相等的數間隔放置的。
這裡用到了three-way partitioning演算法。
three-way partitioning
給定一個陣列,和一個劃分陣列用的目標數,將陣列劃分為小於,等於,大於目標數三部分。
比如對於陣列
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
vector<int> nums{2,1,3,6,5,7,3};
int beg=0, end=nums.size()-1, i=0;
int target=3;
while(i<=end){
if(nums[i]<target) swap(nums[i++],nums[beg++]);
else if(nums[i]>target) swap(nums[i], nums[end--]);
else ++i;
}
for_each(nums.begin(), nums.end(), [](int i){cout<<i<<" ";});
cout<<endl;
return 0;
}
看懂上面的程式碼之後就可以比較容易的理解下面的程式碼了。
class Solution
{
public:
void wiggleSort( vector<int>& nums )
{
if(nums.empty()) return;
int n = static_cast<int>(nums.size());
//find the median
auto midPtr = nums.begin()+ n/2;
nth_element(nums.begin(), midPtr, nums.end());
int median = *midPtr;
//lambda: remap the idnex
auto m = [n](int idx){return (2*idx+1)%(n|1);};
//3-way-partition
int beg = 0, end = n - 1, cur = 0;
while(cur <= end){
if( nums[m(cur)] > median ){
swap(nums[m(cur++)], nums[m(beg++)]);
}
else if(nums[m(cur)] < median){
swap(nums[m(cur)], nums[m(end--)]);
}
else ++cur;
}
}
};
lambda表示式是用來重新對映陣列索引的。
Accessing m(0) actually accesses nums[1].
Accessing m(1) actually accesses nums[3].
Accessing m(2) actually accesses nums[5].
Accessing m(3) actually accesses nums[7].
Accessing m(4) actually accesses nums[9].
Accessing m(5) actually accesses nums[0].
Accessing m(6) actually accesses nums[2].
Accessing m(7) actually accesses nums[4].
Accessing m(8) actually accesses nums[6].
Accessing m(9) actually accesses nums[8].
這樣的話,就自然而言在劃分陣列的時候,把較小的一部分放在了奇數位置,較大的一部分放在了偶數位置,並且因為每次都是間隔了一個數,中間相同的數就會被隔開。
參考
https://discuss.leetcode.com/topic/32929/o-n-o-1-after-median-virtual-indexing/2
相關文章
- LeetCode-Wiggle SortLeetCode
- [LeetCode] 280. Wiggle SortLeetCode
- LeetCode-Wiggle SubsequenceLeetCode
- LintCode-Sort Colors II
- Leetcode每日一題:992.sort-array-by-parity-ii(按奇偶排序陣列Ⅱ)LeetCode每日一題排序陣列
- Leetcode Sort ColorsLeetCode
- Leetcode Sort ArrayLeetCode
- Leetcode-Sort ListLeetCode
- Leetcode-Sort ColorsLeetCode
- Sort List leetcode javaLeetCodeJava
- Sort Colors leetcode javaLeetCodeJava
- Leetcode Insertion Sort ListLeetCode
- [LeetCode] Jump Game IILeetCodeGAM
- Leetcode jump Game IILeetCodeGAM
- Leetcode Spiral Matrix IILeetCode
- Leetcode Path Sum IILeetCode
- Leetcode-Subsets IILeetCode
- Leetcode-Permutations IILeetCode
- Leetcode Unique Paths IILeetCode
- Permutations II leetcode javaLeetCodeJava
- Subset II leetcode javaLeetCodeJava
- LeetCode C++ 376. Wiggle Subsequence【Dynamic Programming】中等LeetCodeC++
- [LeetCode] 451. Sort Characters By FrequencyLeetCode
- [LeetCode] 148. Sort ListLeetCode
- LeetCode | 148. Sort ListLeetCode
- LeetCode每日一題:sort colorsLeetCode每日一題
- LeetCode148:Sort ListLeetCode
- 【LeetCode】Sort Colors 陣列排序LeetCode陣列排序
- Insertion Sort List Leetcode javaLeetCodeJava
- leetcode-90. Subsets IILeetCode
- Leetcode 213 House Robber IILeetCode
- LeetCode-Strobogrammatic Number IILeetCode
- LeetCode-Course Schedule IILeetCode
- LeetCode-H index IILeetCodeIndex
- LeetCode-Majority Element IILeetCode
- LeetCode-Basic Calculator IILeetCode
- LeetCode-Word Pattern IILeetCode
- LeetCode-Paint House IILeetCodeAI