你不可不會的幾種移動零的方法

  • 2021 年 6 月 20 日
  • 筆記

前言

本文主要介紹通過「末尾補零」以及「交換零元素與非零元素」的策略來解答此題,供大家參考,希望對大家有所幫助。

移動零

 

 

解題思路

根據題意,要把數組中所有 0 移動到數組的末尾,還要保持非零元素的「相對位置」,只需要遍歷一遍數組,找出「非零元素」,然後將找出的非零元素替換原數組的元素,原數組中「未替換的元素全部用零去替換」即可。

末尾補零法

「舉例」

以數組 nums =[0,1,0,3,12]為例子,如下圖示。

 

遍歷整個數組,找出所有非零元素。

 

替換

 

遍歷、查找和替換的完整過程,如下動圖示。

 

「說明」

不需要全部查找完數組中的非零元素之和,再去替換,可以「邊查找邊替換」,這樣就不需要「開闢額外空間存儲查找到的非零元素」

Show me the Code

「C」

 1 void moveZeroes(int* nums, int numsSize){
 2     int j = 0;   //  區間[0...j)中存放非零元素
 3     for (int i = 0; i < numsSize; ++i) {
 4         /* 尋找數組中所有的非零元素,並保存在區間[0...j)中 */
 5         if (nums[i] != 0) {
 6             nums[j++] = nums[i]; 
 7         }
 8     }
 9 
10     /* 原數組未被非零元素替換的元素全部置為0 */
11     while (j < numsSize) {
12         nums[j++] = 0;
13     }
14 }

View Code

「C++」

 1 void moveZeroes(vector<int>& nums) {
 2     int j = 0;
 3     for (int i = 0; i < nums.size(); i++) {
 4         if (nums[i] != 0) {
 5             nums[j++] = nums[i];
 6         }
 7     }
 8     
 9     while (j < nums.size()) {
10         nums[j++] = 0;
11     }
12 }

View Code

「Python3」

1 def moveZeroes(self, nums):
2     j, length = 0, len(nums)
3     for i in range(length):
4         if nums[i] != 0:
5             nums[j] = nums[i]
6             j += 1
7     while j < length:
8         nums[j] = 0
9         j += 1

View Code

「Golang」

 1 func moveZeroes(nums []int)  {
 2     j, length := 0, len(nums)
 3     for i := 0; i < length; i++ {
 4         if nums[i] != 0 {
 5             nums[j] = nums[i]
 6             j++
 7         }
 8     }
 9     
10     for j < length {
11         nums[j] = 0
12         j++
13     }
14 }

View Code

「複雜度分析」

時間複雜度:「O(n)」,其中 n 是數組的長度,需要遍歷一遍數組。

空間複雜度:「O(1)」,未開闢額外的存儲空間。

交換法

由於題目的說明中要求「盡量減少操作次數」,因此可以考慮通過「遍歷查找到非零元素,再交換非零元素與當前數組的第一個零元素」的策略,來減少方法一種的補零操作,從而減少操作次數。

「舉例」

還是以數組 nums =[0,1,0,3,12]為例子,其交換過程如下圖示。

由於 nums[1] 為非零元素,nums[0] 為零元素,因此交換它們。

 

其完整查找和交換過程,如下動圖示。

 

Show me the Code

「C++」

 1 void moveZeroes(vector<int>& nums) {
 2     for (int i = 0, k = 0; i < nums.size(); i++) {
 3         if (nums[i] != 0) {
 4             if (i != k) {
 5                 swap(nums[k++], nums[i]);
 6             } else {
 7                 k++;
 8             }     
 9         }
10     }
11 }

View Code

「Python3」

1 def moveZeroes(self, nums: List[int]) -> None:
2     k, length = 0, len(nums)
3     for i in range(length):
4         if nums[i] != 0:
5             if i != k:
6                 nums[k], nums[i] = nums[i], nums[k]
7                 k += 1
8             else:
9                 k += 1

View Code

「Golang」

 1 func moveZeroes(nums []int)  {
 2     k, length := 0, len(nums)
 3     for i := 0; i < length; i++ {
 4         if nums[i] != 0 {
 5             if i != k {
 6                 nums[k], nums[i] = nums[i], nums[k]
 7                 k++
 8             } else {
 9                 k++
10             }
11         } 
12     }
13 }

View Code

「說明」

上述的代碼中都加了「i 是否等於 k」的判斷,這是因為如果數組中的元素都是「非零元素」,就不需要「自己與自己交換」,也算是一個小的優化。

「複雜度分析」

時間複雜度:「O(n)」,其中 n 是數組的長度,需要遍歷一遍數組。

空間複雜度:「O(1)」,未開闢額外的存儲空間。