#283. Move Zeroes
題目描述
給你一個整數陣列nums
,整理非0
值的數字排序,將所有的0
移動到陣列的後面。
你只能在同一個陣列中操作,不能使用複製陣列來完成。
限制條件
- 1 <= nums.length <= 104
- -231 <= nums[i] <= 231 - 1
- 只能在同一個陣列中操作,不能使用額外的空間完成任務。
解題思路
由於不能使用複製陣列的方式來整理數字,所以能夠解決的選項就很少了。
Two Pointers
這題可以使用雙指標來解決,第一個指標用來定位0
值,另外一個指標用來往後搜尋需要往前放的非0
值。 當兩個指標任一達到尾端時,就算陣列整理完成了。
public class Solution {
public int[] Solver(int[] nums){
int zPos = 0;
while(zPos<nums.Length-1){
while(nums[zPos]!=0){
zPos++;
if(zPos>=nums.Length-1) return;
}
for(int i=zPos+1;i<nums.Length;i++){
if(nums[i]!=0){
nums[zPos] = nums[i];
nums[i] = 0;
break;
}
if(i==nums.Length-1) return;
}
}
}
}
複雜度分析:
- 時間複雜度:最差的情況會是兩個指標都要跑一次全部的陣列,像是[0 ... 0 ... 1]這種狀況,總時間為2N,因此時間複雜度為O(N)。
- 空間複雜度:由於是in-place操作,因此空間複雜度為O(1)。
Follow-up
你可以減少執行的次數嗎?
Two Pointers Improvement
上一個解決方式最差會產生讓兩個指標都要走完一次陣列的情況,我們可以稍微調整一下順序,由尋找非0
值的指標為基準,首先先定位最近的0
值位置,然後開始往後找非0
值,這個時候找到的非0
值如果位置比0
值小,代表它位於整理好的位置,如果比0
值大,代表它需要被往前移動到0
值的位置。
以這個順序來執行的話,0
值指標最多只會走到已經整理過的非0
值的末端位置,而非0
值指標會走完全部的陣列,因此執行的次數會略低於上一個解決方法。
public class Solution {
public int[] Solver(int[] nums){
int zPos = 0;
for(int i=0;i<nums.Length;i++){
while(nums[zPos]!=0){
zPos++;
if(zPos==nums.Length) return;
}
if(nums[i]!=0 && i>zPos){
nums[zPos] = nums[i];
nums[i] = 0;
}
}
}
}
複雜度分析:
- 時間複雜度:非
0
值指標一定會跑完全部的陣列,0
值指標最多只會到達非0
值數字的末端,總執行時間為(N< n <2N),因此時間複雜度為O(N)。 - 空間複雜度:由於是in-place操作,因此空間複雜度為O(1)。
學習重點
- 雙指標