LeetCode-MoveZeroes


原始題目

Given an array nums, write a function to move all 0’s to the end of it while maintaining the relative order of the non-zero elements.

中文翻譯

今天團隊大神又帶萌新刷 LeetCode 了,原始題目是 LeetCode 的 Move Zeroes,但是為了挑戰性,加了一點限制

  1. 將數字陣列裡所有 0 的元素移到最後面
  2. 不改變其他數字的排序
  3. 直接在該陣列物件完成操作,不可複製或建立新的陣列

TestCase:

Input: [0,1,0,3,12]
Output: [1,3,12,0,0]

解題

第一個版本

第一個版本就真的像是候捷說的全憑本能程序員,這個版本還算簡單,但進步空間還是很大的,套用了兩次迴圈,複雜度數值應該不會很好看

public void MoveZeroes(int[] nums)
{
    for (var i = 0; i < nums.Length; i++)
    {
        // 如果已經是最後一格,不動作
        if (i == nums.Length - 1) continue;

        // 當前有數值,不動作
        if (nums[i] != 0) continue;

        // 找出下一個不是0的index
        var notZeroIndex = FindNotZero(nums, i);
        if (notZeroIndex == -1) continue; // 找不到,不動作

        // 交換數字
        nums[i] = nums[notZeroIndex];
        nums[notZeroIndex] = 0;
    }
}

private int FindNotZero(int[] nums, int currentIndex)
{
    for (var i = currentIndex; i < nums.Length; i++)
        if (nums[i] != 0) return i;
    return -1;
}

第二個版本

這個版本開始採用了兩個指標,所以變得有點難以理解,最後還是依靠大神提點才搞出了這個版本,原本以為應該是不錯了,但是實際上跑出來的數值,感覺跟第一個版本沒啥明顯差異

public void MoveZeroes(int[] nums)
{
    var i = 0;
    var j = 1;
    while (j < nums.Length)
    {
        // 如果前面的為0,後面不為0,就交換
        if (nums[i] == 0 && nums[j] != 0)
        {
            nums[i] = nums[j];
            nums[j] = 0;
        }
        // 如果兩者都為0,那後面的 + 1
        else if (nums[i] == 0 && nums[j] == 0)
        {
            j++;
        }
        // 否則往下一個數字開始處理
        else
        {
            i++;
            j = i + 1;
        }
    }
}

第三個版本

最終由大神說明最終版本的思路,一樣是採用兩個指標,指標 right 用來順序跑回圈往下走;指標 left 就是用來交換數值用的

  1. left 指標都必須指在 0 上面等著被交換
  2. right 指標只有在不是 0 的時候才做交換
public void MoveZeroes(int[] nums)
{
    for (int left = 0, right = 0; right < nums.Length; right++)
    {
        if (nums[right] != 0)
        {
            int temp = nums[right];
            nums[right] = nums[left];
            nums[left] = temp;
            left++;
        }
    }
}

程式碼很簡短,速度也很快,第三種版本有一種豁然開朗的感覺,但是一開始就算知道思路,還是卡關很久,附上三個案例的步驟

陣列中沒有 0,在每一個步驟,left 實際上都是自己跟自己交換,然後最終 left 指標再+1

在步驟 3 的時候,right 碰到了 0,所以跳過不做事情;所以 left 也就被固定下來 (只有 right 碰到不是 0 的時候,left 才會增加)