283 移动零 数组变换

题目
题目描述:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

憨憨方法

# 憨到了极限
def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        notZero = []
        count = 0
        while True:
            try:
                nums.remove(0)
                count+=1
            except:
                break
        while True:
            if count==0:
                break;
            else:
                nums.append(0)
                count-=1
# 优雅了许多,但依然是效率低下的憨憨
def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        for i in nums[:]:
            if i==0:
                nums.append(0)
                nums.remove(0)

下面是官方的例子,官方称其为局部空间优化,思路和上面的python代码大同小异,但是效率却差很多。进一步分析代码,python中remove的复杂度为O(n),也就是说上面写的代码的复杂度为O(n^2)

cpp:

void moveZeroes(vector<int>& nums) {
        int n = nums.size();

        // Count the zeroes
        int numZeroes = 0;
        for (int i = 0; i < n; i++) {
            numZeroes += (nums[i] == 0);
        }

        // Make all the non-zero elements retain their original order.
        vector<int> ans;
        for (int i = 0; i < n; i++) {
            if (nums[i] != 0) {
                ans.push_back(nums[i]);
            }
        }

        // Move all zeroes to the end
        while (numZeroes--) {
            ans.push_back(0);
        }

        // Combine the result
        for (int i = 0; i < n; i++) {
            nums[i] = ans[i];
        }
    }

根据这个思路,改进了下python的代码,其中遇到了些小插曲qwq,需要再将拷贝这方面好好钻研下了

def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        count = 0
        notZero = []
        for x in nums:
            if x == 0:
                count+=1
            else:
                notZero.append(x)
        """注意!直接赋值是引用,copy和deepcopy也会改变地址,
        但是和左右两个的地址都不一样?所以输出的既不是notZero里的也不是后来的nums里的,
        而是最开始的nums"""
        # nums = notZero.copy()
        while count:
            notZero.append(0)
            count-=1

        # 采用循环遍历的赋值方法,其他的方法都不行qwq
        for i in range(len(nums)):
            nums[i] = notZero[i]

空间局部最优,操作局部优化(双指针)

思路:一个记录索引,每次检测到非0元素则+1,将非零元素放到索引处(实际操作时其实是先放,索引再加)。第一次遍历完后记录索引正好到了总长-非零的长度,即索引(包括)之后的所有值都为0。
复杂度=O(n)+O(m)=O(n)

void moveZeroes(vector<int>& nums) {
        int lastNonZeroFoundAt = 0;
        // If the current element is not 0, then we need to
        // append it just in front of last non 0 element we found. 
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] != 0) {
                nums[lastNonZeroFoundAt++] = nums[i];
            }
        }
        // After we have finished processing new elements,
        // all the non-zero elements are already at beginning of array.
        // We just need to fill remaining array with 0's.
        for (int i = lastNonZeroFoundAt; i < nums.size(); i++) {
            nums[i] = 0;
        }
    }

遍历替换 全局最优

空间复杂度: O(1) 吧?只用了几个变量的空间,没有开辟额外的储存空间
时间复杂度: O(n) 从头到尾遍历一次(击败90%+)
思路:两个变量,存索引,然后每次循环交换其值,索引每次循环都会增加,只是其中一个有条件:不为零。所以不难想象,两个索引,分别存的是第一个零的索引,和自然增长的索引,也就是每次循环会将下一个不为零的元素与第一零交换位置,剩下的零自然也就在后面了。实质也只是在局部最优的基础上进行了改进,不要再置零操作。

def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        i = j = 0
        for i in range(len(nums)):
            if nums[i] != 0:
                nums[j] , nums[i]= nums[i] , nums[j]
                j += 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值