【LeetCode & 剑指offer刷题】查找与排序题14:Wiggle Sort(系列)

【LeetCode & 剑指offer刷题】查找与排序题14:Wiggle Sort(系列)

【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

Wiggle Sort II
Given an unsorted array   nums , reorder it such that   nums[0] < nums[1] > nums[2] < nums[3]... .
Example 1:
Input: nums = [1, 5, 1, 1, 6, 4] Output: One possible answer is [1, 4, 1, 5, 1, 6] .
Example 2:
Input: nums = [1, 3, 2, 2, 3, 1] Output: 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?

C++
 
//问题:摆动排序,a[0] < a[1] > a[2] < a[3]...
//??没看懂,以后再看
//方法二:利用快排中一步(nth_element函数)将序列分成两段,以中值为枢轴,从各段段首(或段尾)开始选数
//思路解析:假设排序后为a1 a2...an mid b1 b2...bn,则组织为a1 b1 a2 b2...
//此法时间复杂度为O(n),如果没有O(1)的空间复杂度,比较简单,正是这个限制增加了复杂度
class Solution {
public :
    void wiggleSort ( vector < int >& nums ) {
        int m = nums . size ();
        auto mptr = nums . begin () + ( m - 1 )/ 2 ;
        nth_element ( nums . begin (), mptr , nums . end ());
        int median = * mptr ;
        int i = 1 ;    // position for the larger values: start with first odd index
        int j = (( m - 1 ) & 1 ) ? m - 2 : m - 1 ;   // position for the smaller values: start with last even index
        for ( int l = 0 ; l < m ; ++ l ) {
            if ( nums [ l ] > median ) {   // fill the large element
                if ( l <= i && ( l & 1 )) continue ;        // skip the elements which are  already checked: 1, 3, 5, ..., i
                swap ( nums [ l --], nums [ i ]);
                i += 2 ;
            } else if ( nums [ l ] < median ) {   // fill the smaller element
                if ( l >= j && ( l & 1 ) == 0 ) continue ;      // skip the elements whcih are checked: j, j + 2, ..., lastEvenIndex
                swap ( nums [ l --], nums [ j ]);
                j -= 2 ;
            }
       }
    }
};
// 方法一:排序后,分成两段,从各段末尾依次取数(可以避免相等数弄在一起)
// 不过此法的时间复杂度为 O(nlogn),空间复杂度为O(n),不满足题意
// 思路解析:假设排序后为 a1 a2...an b1 b2...bn, 则组织为 an bn an-1 bn-1...
class Solution
{
public :
    void wiggleSort ( vector < int >& a )
    {
        int n = a . size ();
        sort ( a . begin (), a . end ());
        if ( n <= 2 ) return ; // 小于两个元素时,直接退出
      
        vector < int > temp = a ;  
        int i = 0 , j =(n-1)/2, k=n-1; //i 用来遍历 a, j 用来遍历 temp 第一段(从末尾开始), k 用来遍历第二段。
        for ( i = 0 ; i < n ; i ++)
        {
            a [ i ] = ( i & 1 )? temp [ k --]: temp [ j --]; // 如果i为奇数,取第二段的数(较大),如果为偶数,取第一段的数(较小)
            // 注:当 n 为奇数时,两段长度不等,第一段比第二段多 1 ,但是上述等式可以保证最后一个数 a[n-1] 选择 temp[0]
        }
    }
};
/*
//摆动排序,a[0] < a[1] > a[2] < a[3]...
//要得到O(n)时间复杂度,O(1)空间复杂度,可以借鉴wiggle sort I(a[0] <= a[1] >= a[2] <= a[3]...)中的思路
//i为奇数时,a[i]>a[i-1], 偶数时,a[i]
//测试结果表明,对于序列中有多个连续相等数时,此方法不行,因为按照交换策略,相等的数会交换,但是交换后并不会满足
//i为奇数时,a[i]>a[i-1], 偶数时,a[i]
class Solution
{
public:
    void wiggleSort(vector& a)
    {
        int n = a.size();
        if(n <= 1) return; //元素个数少于1个时,退出
       
        for(int i = 1; i < n; i++)
        {
            if((i%2 == 1 && a[i]<=a[i-1]) || (i%2 == 0 && a[i]>=a[i-1]))
            {
                swap(a[i], a[i-1]);//如果不符合摆动规律则交换
            }
        }
    }
};
*/
 
Wiggle Sort I
Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= nums[2] <= nums[3]....
For example, given nums = [3, 5, 2, 1, 6, 4], one possible answer is [1, 6, 2, 5, 3, 4].
 
这道题让我们求摆动排序,跟 Wiggle Sort II 相比起来,这道题的条件宽松很多,只因为多了一个等号。由于等号的存在,当数组中有重复数字存在的情况时,也很容易满足题目的要求。这道题我们先来看一种时间复杂度为 O(nlgn) 的方法, 思路是先给数组排个序,然后我们只要每次把第三个数和第二个数调换个位置,第五个数和第四个数调换个位置,以此类推直至数组末尾 ,这样我们就能完成摆动排序了,参见代码如下:
 
//解法一:
// Time Complexity O(nlgn)
class Solution {
public :
    void wiggleSort ( vector < int > & nums ) {
        sort ( nums . begin (), nums . end ());
        if ( nums . size () <= 2 ) return ;
        for ( int i = 2 ; i < nums . size (); i += 2 ) {
            swap ( nums [ i ], nums [ i - 1 ]);
        }
    }
};
 
这道题还有一种O(n)的解法,根据题目要求的nums[0] <= nums[1] >= nums[2] <= nums[3]....,我 们可以总结出如下规律:
当i为奇数时,nums[i] >= nums[i - 1]
当i为偶数时,nums[i] <= nums[i - 1]
那么我们只要对每个数字, 根据其奇偶性,跟其对应的条件比较,如果不符合就和前面的数交换位置即可 ,参见代码如下:
 
//解法二:
// Time Complexity O(n)
class Solution {
public :
    void wiggleSort ( vector < int > & nums ) {
        if ( nums . size () <= 1 ) return ;
        for ( int i = 1 ; i < nums . size (); ++ i ) {
            if (( i % 2 == 1 && nums [ i ] < nums [ i - 1 ]) || ( i % 2 == 0 && nums [ i ] > nums [ i - 1 ])) {
                swap ( nums [ i ], nums [ i - 1 ]);
            }
        }
    }
};
来源: http://www.cnblogs.com/grandyang/p/5177285.html

 

posted @ 2019-01-05 20:17 wikiwen 阅读( ...) 评论( ...) 编辑 收藏

你可能感兴趣的:(【LeetCode & 剑指offer刷题】查找与排序题14:Wiggle Sort(系列))