move zeroes --java 解法 同leetcode 283

題目是我做一個公司的筆試題目出現的,後來發現leetcode 上也有。
參考:leetcode 283

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.

For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].

Note:
You must do this in-place without making a copy of the array.
Minimize the total number of operations.

題目描述

給定一個數組,將數組中的0元素全部移動到數組的尾部,並保持原數組的非0元素的在數組中出現的順序。
例如 輸入nums = [0, 1, 0, 3, 12], 輸出[1, 3, 12, 0, 0]。

要求

1.只能對數組進行原地操作,不能額外借用數組或者複製數組;
2.時間複雜度越小越好。

思路

在不允許使用輔助數組的情況下,只能對數組本身進行操作。根據題意,由於我們要找出數組中的0元素和非0元素,顯然,我們需要兩個指針來分別標記他們,然後交換兩指針上的值來達到目的。
接下來的三種方法,無論哪一種思路,實際上都是用到了兩種指針來標記0元素和非0元素的目的。

方法一

順序掃描數組,用一個指針iPointer從0開始,可以理解爲標記數組中非0元素的個數,遇到非0元素時,順序的直接將其移動到數組的前面即iPointer所指位置,數組掃描完畢時,iPointer指向數組中的最後一個非0元素。然後將iPointer後面的部分的數組元素全部補0即可。這種思路的代碼也最容易理解。

class Solution {
    public void moveZeroes(int[] nums) {
        //方案一
        int iPointer = 0;
        int len = nums.length;
        for(int i=0; i<len;++i)
        {
            if(nums[i] != 0)
                nums[iPointer++] = nums[i];//直接將遇到的非0元素
        }
        if(iPointer != 0)
        {
            for(; iPointer<len; iPointer++)
                nums[iPointer] = 0;
        } 
   }
}
方法二

實際上算是方案一的改進版,既然每次找到了非0元素,幹嘛不多用一個指針,標記一下0元素,讓其兩者直接交換,而無須在數組掃描完畢後再對數組剩餘部分置0了。
流程:iPointer=0用來從頭掃描數組,jPointer=0用來標記0元素。兩者都從頭開始移動指針。IPointer碰到非0元素時停下,將其跟jPointer指向的0元素交換,交換完,j向前移動一個位置,由於iPointer掃描數組時是遇到非0元素才停下,交換完後,jPointer移動一個指針指向的肯定是0元素,實際上在交換元素的過程中,i,j指針之間的元素一定都是0

class Solution {
    public void moveZeroes(int[] nums) {

        if(nums == null || nums.length == 0)
        {
            return;
        }

        int len = nums.length;
        for(int i=0, j=0; i < len; ++i)
        {
            if(nums[i] != 0 )//i指針實際上依次指向非0元素時,纔有交換
            {
                /*nums[j] = nums[i];//交換完,將j指針指向0元素
                nums[i] = 0;
                ++j;*///這樣做的問題就在於當數組第一個元素或者都是非0元素時就會出現問題

                /*nums[i] = nums[i] + nums[j];//或者用異或a=a^b;b=a^b;a=a^b;
                nums[j] = nums[i] - nums[j];
                nums[i] = nums[i] - nums[j];*///這個只適合交換數組中不同位置上的數字,如果i=j時就會改變nums[i]的值

                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                j++;//i,j指針交換完,將j指針指向0元素
            }
        }       
    }
}
方法三

實際上思路跟方法二完全一樣。

class Solution {
    public void moveZeroes(int[] nums) {

        /**
         *思路:維持兩個指針:一個指向非0元素(iPointer),一個指向0元素(jPointer)
         * 一開始i,j指針同時都從0開始往後移動;
         * 先移動i指針遇到非0元素停下,j指針遇到0元素停下;
         * 交換i,j指針上的值,繼續移動;
         * 我們會發現:i,j指針之間都是0元素
         */
        int len = nums.length;
        int iPointer = 0;
        int jPointer = 0;
       while (iPointer < len)
        {
            if(nums[iPointer] != 0)//在遇到0元素時,只有i指針移動
            {
                if (iPointer != jPointer) {
                    nums[jPointer] = nums[iPointer];
                    nums[iPointer] = 0;
                    jPointer++;
                } else {
                    jPointer++;//在遇到非0元素時,i,j指針同時移動
                }

            }
            iPointer++;//在遇到0元素時,只有i指針移動////在遇到非0元素時,i,j指針同時移動
        }        
    }
}

通過比較三種方法,實質上都是通過雙指針來完成原地操作的,之所以寫第三種方法,是我們能更直觀的看到雙指針的操作。以上三種方法都在leetcode上Accepted的。雙指針的思路解決辦法感覺還是很重要的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章