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.
Example:
Input: [0,1,0,3,12]
Output: [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.
给定一个数组nums,写一个函数,将数组中所有的0挪到数组的末尾,而维持其他所有非0元素的相对位置。
举例:nums=[0,1,0,3,12],函数运行后结果为[1,3,12,0,0]
注:in-place:原状
方法一:
创建一个新的数组,将原数组中非0的数字拷贝到该数组中。遍历新的数组,将非零数据拷贝到原数组中,其余位置用0补齐
代码:
class Solution {
public void moveZeroes(int[] nums) {
ArrayList<Integer> newArray=new ArrayList();
for(int i=0;i<nums.length;i++){
if(nums[i]!=0)
newArray.add(nums[i]);
}
for(int i=0;i<newArray.size();i++)
nums[i]=newArray.get(i);
for(int i=newArray.size();i<nums.length;i++)
nums[i]=0;
}
}
添加数据到新数组中时遍历了一次原数组,拷贝数据时又遍历了一遍数组。时间复杂度为O(n)
开辟了一个与原数组差不多的空间,空间复杂度为O(n)
方法二:
方法一中,另外开辟了一个空间,所以空间复杂度为O(n)。那么,能不能不开辟空间呢?可以设置一个指针,初始值为0,当遇到第一个不为0的数后,将其赋值到索引为k的位置,k++,移动组成的空间为[0....k);然后从k开始遍历,将其余位置补0就可以了。
此时时间复杂度为O(n),空间复杂度为O(1)级别。没有额外使用任何空间,完成了这个操作
代码:
public void moveZeroes(int[] nums) {
int k=0; //在nums中,[0...k]的元素均为非0元素
//遍历到第i个元素后,保证[0...k)的元素均为非0元素
//都按照顺序排列在[0...k]中
for(int i=0;i<nums.length;i++){
if(nums[i]!=0)
nums[k++]=nums[i];
}
//将nums剩余的位置放置为0
for(int i=k;i<nums.length;i++)
nums[i]=0;
}
方法三、
方法二中,虽然把前面的非零元素放置好后,还需要额外的操作,将其余位置置为0.有没有可能,将非零元素移动到前面以后,其余位置也直接把0放到后面呢?将非零元素和零位置的数据进行交换
代码:
class Solution {
public void moveZeroes(int[] nums) {
int k=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=0){
swap(nums,k++,i);
}
}
}
private void swap(int[] nums,int l,int r){
int temp=nums[l];
nums[l]=nums[r];
nums[r]=temp;
}
}
方法四:
在方法三中,如果所有元素都是0,则还会进行一次交换操作,但是如果加上判断,只有元素不相等的时候才进行交换,此时如果都是零的话,只是扫了一遍整个数组。交换操作是非常费时的
代码:
class Solution {
public void moveZeroes(int[] nums) {
int k=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=0){
if(nums[k]!=nums[i]){
swap(nums,k++,i);
}else{
k++;
}
}
}
}
private void swap(int[] nums,int l,int r){
int temp=nums[l];
nums[l]=nums[r];
nums[r]=temp;
}
}