Move Zeroes(移动零元素)

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.(给定一个数组,将数组中值为0的元素移动到所有非0元素的后面,而且非0元素之间保持原始的相对位置)

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

1.个人分析
先考虑用最简单直接的方法实现,要把所有的0元素放到非0元素之后,可以逐个遍历数组元素,设置两个指针分别指向数组头p1和尾p2,p1始终指向0元素,p2始终指向非0元素,头部指针开始遍历,如果是0则将该元素与p2指向的元素进行交换,不断地进行该操作直到p1>=p2.

2.个人解法

void moveZeroes(int* nums, int numsSize) 
{
    if(nums == NULL)
        return;

    int i = 0 , j, count = 0;
    for(; i < numsSize; ++i)
        if(0 == nums[i])
            ++count;

    for(i=0; i < numsSize;)
    {
        if(0 == nums[i])
        {               
            for(j = i + 1; j < numsSize; ++j)
                nums[j-1] = nums[j];
        }
        else
            ++i;
    }

    i = numsSize - 1;
    while(count--)
    {
        nums[i] = 0;
        --i;
    }
}

思路是首先得到数组中0元素的个数,然后用i去遍历每个元素,找到零元素,并将该元素后面的所有元素往前移一个位置,直到i遍历到最后一个位置;最后是根据前面得到的0元素个数,从后往前填充0。

结果显示虽然能够通过常规的测试用例,但始终无法通过个别特殊用例,比如[1,0,0],在运行到第二个for循环中时,i指向0元素后,循环体只会运行第一条if语句,而++i无法执行,所以造成死循环。另外这个解决方法的时间复杂度是O(n^2)的,效率很低。

3.参考解决方法

void moveZeroes2(int *nums, int numsSize)
{
    int j = 0;
    // move all the nonzero elements advance
    for (int i = 0; i < numsSize; i++) 
    {
        if (nums[i] != 0) 
            nums[j++] = nums[i];            
    }

    for (;j < numsSize; j++) 
        nums[j] = 0;        
}

这里给出的方法与自己的想法是类似,都是先通过两个指针遍历数组,将非0元素移动到前面的位置,最后用0来填充数组后面剩余的位置。它这里的i和j两个指针设计的非常巧妙,用指针i寻找非0元素,用j指向0元素或者已被移元素的位置(可理解为空位)。

4.总结
个人在问题的大体方向上是对的,但对于细节处理的不好,在如何设置和移动两个指针方面没有一个准确的定位,导致只满足部分测试用例,后面就不得不为了通过某些用例而修改代码,然而结果是拆东墙补西墙,某个特殊测试用例虽通过了,但其他的特殊用例又无法通过了。其实这里自己依然犯了经常会犯的错误,就是在思路上容易一根筋地陷下去而无法跳转到其他的思路上去,如果发现实在走不下去的时候也只能缴械投降了。看来训练自己的思维转换能力依然是当务之急,以后要不断地进行心理暗示,为什么不尝试一下从其他的角度来解决呢?

PS:

  • 题目的中文翻译是本人所作,如有偏差敬请指正。
  • 其中的“个人分析”和“个人解法”均是本人最初的想法和做法,不一定是对的,只是作为一个对照和记录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值