LeetCode # 283 陣列裡的0全都移到最後,其他保持原順序

IAMIDA發表於2020-11-19

輸入: [0, 1, 0, 3, 12]
輸出: [1, 3, 12, 0, 0]
方法一(直接求非零元素的最終位置):

  1. 用一個變數zero_num記錄到目前為止遇到0的個數,當元素為0時就將其加一,然後跳過繼續遍歷下一個數;
  2. 如果當前的數字不是0,根據zero_num我們可以知道它的最終位置。比如輸入陣列中,1之前出現過一個0,把這個0去除,等同於1要往前移一位;又如12之前出現過兩個0,把這兩個0去除,等同於12最終要往前移兩位。所以每個非零數字當前下標減去zero_num就是它最終位置的下標,代表它應該往前跳zero_num步;
  3. 陣列全部遍歷完後,還剩最後一步:將統計的zero_num個0放到最後。
####### 原始版
 l = len(nums)
 zero_num = 0   # 記錄到目前為止遇到幾個0了
   for i, num in enumerate(nums):
       if num == 0:
           zero_num += 1
           continue
       nums[i-zero_num] = num
   # 最後補0
   for j in range(l-zero_num, l):
       nums[j] = 0
####### 簡化版
nums.sort(key=lambda x: x == 0)   # True在False之前

方法二(雙指標分別記錄已排序和未排序的位置):

  1. 左指標指向已排好序的最後一個數字(最終位置已經確定了,並且其左側的都是非零數),右指標指向還沒排序的第一個數字;
  2. 如果右指標指的數字為0,則繼續往後遍歷;如果不為0,那就要讓左指標向後一位,並將此時的左右交換,然後右指標繼續往後;
  3. 這種方法利用了左指標和右指標定義對應的性質:
    左指標左邊的數都是已經排好的非零數,每次右指標找到新的非零數時,左指標會往後一位,如果此時左和右之間有間隔,那間隔的這些數字一定都是0,比如left =0, right = 3時,陣列變成了[1, 0 ,0, 3, 12],我們發現右指標所指的3不為0,就會讓左指標向後一位,指向1後面的0,然後讓0和3互換,這樣就會把0不斷往後換,但是顯然這中間有許多冗餘操作,每次都要移動不同的0.
l = len(nums)
left, right = -1, 0
while right<l:
    if nums[right]!=0:
        left += 1
        temp = nums[left]
        nums[left] = nums[right]
        nums[right] = temp
    right += 1

相關文章