LeetCode#905 - 按奇偶排序數組
題目
給定一個非負整數數組 A,返回一個由 A 的所有偶數元素組成的數組,後面跟 A 的所有奇數元素。
你可以返回滿足此條件的任何數組作為答案。
輸入:[3,1,2,4]
輸出:[2,4,3,1]
輸出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也會被接受。
解題思路
根據題目的描述,我們可以看到這道題只有一個要求,那就是將數組中的偶數全部挪到奇數的前面,另外順序不計。
解法一
我看到這個題的第一反應是可以使用插入排序來解決這個問題,插入排序主要使用兩個for循環,一個用來遍歷整條數組,另一個用來掃描已排好順序的列,將元素插入到合適的位置,再使用if語句來判斷是否滿足兩個元素交換的條件。
對於這道題兩個元素交換的條件是當前索引位置的元素是偶數且它的前一個位置是奇數,於是有了第一種解法。
public static int[] SortArrayByParity(int[] A) { int length = A.Length; for (int i = 1; i < length; i++) { for (int j = i; j > 0; j--) { if(A[j]%2==0&&A[j-1]%2==1) //當前索引位置元素是偶數且前一個位置是奇數 { int temp = A[j]; A[j] = A[j - 1]; A[j - 1] = temp; } } } return A; }
這種解法其實就是將簡單插入排序的if
語句換了一下而已。因為代碼中只使用一個temp
變量作為兩個元素交換的‘中介’,所以它的空間復雜度為O(1),時間復雜度也就是簡單插入排序的時間復雜度,即O(n^2),但是實際肯定要比插入排序快,因為題目並不要求有序。
解法二
第二種解法的思路是,創建一個A數組長度一樣的數組B,同時新建兩個索引變量i
、j
。其中,i指向數組的第一個位置,j指向數組的最後一個位置。
程序開始對A進行遍歷,遍歷的同時對每個元素進行奇偶判斷。如果是偶數,就把當前元素放在B[i]
的位置,同時i
自增1;如果是奇數,就放在B[j]
的位置,同時j
自減1。
public static int[] SortArrayByParity(int[] A) { int length = A.Length; int[] B = new int[length]; int i = 0, j = length-1; foreach (var item in A) { if(item%2==0) { B[i] = item; i++; } else { B[j] = item; j--; } } return B; }
在第二種解法種,我們創建了和數組A一樣長度的數組B,所以它的空間復雜度是O(n)。另外,我們只對數組A進行了一次遍歷,所以時間復雜度是O(n)。
結語
在物理內存中,數組是一塊連續的區域,元素是一個挨著一個的,就像火車車廂一樣,我覺得這種對數組元素位置進行“重排”的題目,基本就兩種解題思路:一種是挪動元素位置;另一種就是創建新數組,將舊數組中滿足條件的元素重新插入新數組中。我在網上也有看到其他的解題方式,例如利用過濾器找出數組中的偶數和奇數,然後再將分解出來的偶數數組和奇數數據進行連接,我覺得本質上和第二種解法是一樣的。
如果你還有更好的優化方法,歡迎在評論留言探討。
LeetCode#905 - 按奇偶排序數組