1. 程式人生 > >【死磕演算法之1刷leetcode】——324 Wiggle Sort擺動序列2

【死磕演算法之1刷leetcode】——324 Wiggle Sort擺動序列2

題目描述

Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]…
Example:
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?

題目解析:

這道題在wiggle sort I的基礎上進行了改動(題解見【死磕演算法之1刷leetcode】——376 Wiggle Sort擺動序列),陣列間元素直接以> 、<號進行比較,重複元素的放置變得關鍵。

方法1:
陣列按升序排序,完成後將陣列一分為二(small half元素個數和陣列的偶數索引個數大小一致)small half倒序對應放置在陣列偶數索引位置上(nums[0] ,nums[ 2] ,nums[4] …),將陣列的large half倒序對應放置在陣列奇數索引上(nums[1],nums[3],nums[5]…)
圖來自leetcode discuss 題解


我們看到在奇數索引位置的陣列元素,比兩側元素大。在演算法中是否有可能出現奇數索引位置的陣列元素和某一側元素相等的情況?

設L>M>S,接下來討論數組裡有重複元素是否會產生兩個重複元素相鄰的結果。
首先要明確,在當前演算法下,在一個half 裡面的重複元素是不會彼此相鄰的。也就是說,來自不同half 的M才有可能造成重複元素相鄰的情況

陣列元素為7時,3個M是可以滿足Wiggle sort條件的, 陣列元素為8時,4個M是可以滿足條件的,總結一下,大小為n的陣列中,M的個數小於floor(n)是不會出現重複元素相鄰的情況的。
在這裡插入圖片描述在這裡插入圖片描述
M是small half裡面最大的(在最左邊一側),是large half裡最小的(在最右邊一側)。由於是兩個half倒序排列賦值,所以合併之後來自不同half 的兩個M也相隔甚遠。

當M 的個數大於floor(n) 時:

1.若n為偶數,結果一定會出現兩個M相鄰的情況。
如8個元素,SMMMMMLL,將S、L、L將M全部隔開是不可能實現的。

2.若n為奇數,只有一種情況wiggle sort是有解的:M的個數等於floor(n)+1且陣列其他非M元素均為L

M的個數等於floor(n)+1,此時只能將M放置在所有的偶數索引位置,陣列中其他所有元素(放在奇數索引位置)只能為L,不然會出現偶數索引位置的值大於某奇數索引位置值,不滿足wiggle sort性質。

題目說明表示輸入資料都是有效解的,那麼用這個演算法一定可以找到有效解。
python程式碼實現:


class Solution:
    def wiggleSort(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        nums.sort()
        half  = len(nums[::2])#避免賦值時大小對不上
        #i為索引,當i為偶數(字元當前個數為奇數),被nums的倒序smaller part替換
        #i為奇數(字元當前個數為偶數),被nums的倒序larger part替換
        nums[::2],nums[1::2] = nums[:half][::-1],nums[half:][::-1]
程式碼注意事項

在實現過程中,遇到了幾個問題,現記錄如下:
1、用切片表示陣列偶數索引的數量要與劃分的smaller half的個數一致。
相關程式碼: half = len(nums[::2]),也就是half是由len(nums[::2])決定的,即len(nums[:half]) == nums[::2]
同時nums[1::2]表示陣列中奇數索引的數量

len(nums[1::2]) == len(nums[:])-len(nums[::2]) == len(nums[:])-len(nums[:half]) ==len(nums[half:])

賦值雙方陣列大小一致,最後一行程式碼可順利執行。

2、陣列排序方法:

nums.sort()#時間複雜度為O(nlog(n)),預設升序排列
nums.sort(reverse = True)#降序排列

或者

   nums = sorted(nums)#預設升序排列
   nums = sorted(nums,reverse = True)#降序排列

注意:
nums.sort()返回值為None,因此nums= nums.sort()之後nums就是NoneType型別了,不能起到排序作用。

Follow up:時間複雜度為O(n)的演算法

再續