LeetCode刷题系列---283. 移动零

LeetCode刷题系列---283. 移动零

  • 题目
    • 示例
  • 解题
    • 解题思路1
      • 本地代码
      • 提交代码
    • 解题思路2
      • 本地代码
      • 提交代码
    • 别人的题解

题目

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
必须在原数组上操作,不能拷贝额外的数组。
做题直接到移动零

示例

输入

[0,1,0,3,12]

输出

[1,3,12,0,0]

解题

解题思路1

从后往前遍历,遇到0,就把他后边的所有非零位置往前复制一位,最后一位非零的位置赋值为0。
该算法的时间复杂度是O(n^2)的,提交以后,时间只优于20%的结果。

本地代码

#include 
#include 

using namespace std;

int n;
vector<int> nums;

void moveZeroes(){
	int k = 0;
	for(int i=n-1; i>=0; i--){
		if(nums[i] == 0){
			int j=i+1;
			for(; j<n-k; j++){
				nums[j-1] = nums[j];
			}		
			k++;
			nums[n-k] = 0;
		}
	}	
}

int main(){
	scanf("%d", &n);
	int t, i=0;
	while(i<n){
		scanf("%d", &t);
		nums.push_back(t);
		i++;
	}
	
	moveZeroes();

	for(int i=0; i<n; i++)
		printf("%d ", nums[i]);
	printf("\n");
	
	return 0;
}

提交代码

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
    	int n = nums.size();    
		int k = 0;
		for(int i=n-1; i>=0; i--){
			if(nums[i] == 0){
				int j=i+1;
				for(; j<n-k; j++){
					nums[j-1] = nums[j];
				}		
				k++;
				nums[n-k] = 0;
			}
		}	
    }
};

解题思路2

其实并不需要每次都往前复制一位。只需要把非零的数放在正确的位置,最后的位置赋值为0即可。
双指针法。声明一个变量k记录0出现的次数,以及两个指针,一快一慢。从前往后遍历,遇到0则k加一。快指针走到非零位置将值复制到满指针的位置。
时间复杂度O(n)。

本地代码

#include 
#include 

using namespace std;

int n;
vector<int> nums;

void moveZeroes(){
	//solution 2
	int k = 0;  //0出现的次数
	int p=0, q=0; //两个指针
	while(q<n){
		if(nums[q] == 0){
			q++;
			k++;
		}
		else
			nums[p++] = nums[q++];	
	} 
	for(int j=n-1; j>=n-k; j--){
		nums[j] = 0;
	}
}

int main(){
	scanf("%d", &n);
	int t, i=0;
	while(i<n){
		scanf("%d", &t);
		nums.push_back(t);
		i++;
	}
	
	moveZeroes();

	for(int i=0; i<n; i++)
		printf("%d ", nums[i]);
	printf("\n");
	
	return 0;
}

提交代码

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n = nums.size();
        int k = 0;  //0出现的次数
		int p=0, q=0; //两个指针
		while(q<n){
			if(nums[q] == 0){
				q++;
				k++;
			}
			else
				nums[p++] = nums[q++];	
		} 
		for(int j=n-1; j>=n-k; j--){
			nums[j] = 0;
		}
    }
};

结果差别显著
在这里插入图片描述
LeetCode刷题系列---283. 移动零_第1张图片

别人的题解

本来觉得自己的结果还不错,结果看到评论区和官方题解的时候,发现还是有改进空间的。

  1. 不需要另外声明一个用来记录出现了多少个零的变量,慢指针后边的所有位置都置零就对了。
  2. 可以在快指针扫过的时候,如果快指针不等于满指针,把该位置的非零值复制到前边,然后直接把该位置置0。最后一遍扫完的时候就不需要再把满指针后边的元素置0了。

别人的代码↓

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int i = 0;
        for (int j=0; j<nums.size(); ++j)
            if (nums[j] != 0 && j!=i){
                nums[i++] = nums[j];
                nums[j] = 0;
            }
            else if (nums[j]!=0 && j==i)
                ++i;
    }
};

参考评论区和官方题解

你可能感兴趣的:(LeetCode刷题)