每日一题(4)——移动零(双指针)

Leecode 2024.3.15

4.移动零

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

请注意 ,必须在不复制数组的情况下原地对数组进行操作。
 

示例 1:

输入: nums = [0,1,0,3,12]

输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]

输出: [0]

提示:

1 <= nums.length <= 104

-231 <= nums[i] <= 231 - 1

进阶:你能尽量减少完成的操作次数吗?


个人解法

思路:

不复制数组,那只能使用指针进行操作了。

所以就有了最简单的思路,建立两个指针left和right,left去遍历nums,而right一直在left之后去搜索:

当left指针遇到0时,让right指针去找在left右边的非0值,找到之后使用nums[left], nums[right] = nums[right], nums[left]去交换list数组的元素,把遇到的第一个非0值换到前面。

按照这个思路,left遍历完一遍数组,就能保证达到题目的要求。

from typing import List
class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # 两个指针
        if len(nums)>1:
            for left in range(0, len(nums)-1):
                if nums[left]==0:
                    for right in range(left+1, len(nums)):
                        if nums[right]!=0:
                            nums[left], nums[right] = nums[right], nums[left]
                            break

time:1586ms(6.87%)

mem:17.37MB(71.73%)


优化

过是过了,一看这个耗时,又要头疼了。

用到了两次循环一定会出现这个问题,现在我们来优化代码:

我们仔细回顾一下两个指针的作用和动作:

在上面的代码中,左边的指针需要遍历完全部nums,去找为0的元素;右边的指针在找非0元素。

这个逻辑是没有问题的,我们从另一个角度来想这个问题:我们要做的其实是把非0元素全部排在list前面。因此:

我们不需要管左边的left指针是不是0,right指针和left指针都从nums的起点出发,我们要做的事情就是,让快指针right遇到的非0值全部排到数组的前面,left指针只需要记录right指针遇到的非0值需要放的位置,出现一个非0值就交换一次,然后left右移一位即可。

class Solution:
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        left = 0 # 慢指针,left
        for right in range(len(nums)):  # 快指针,right,遍历数组
            # 核心的交换步骤:如果当前right不为0,则交换到左侧,把非0数往左侧移动就对了
            if nums[right]: 
                nums[left], nums[right] = nums[right], nums[left]
                left += 1 # left被非0元素填占了后,挪开一个位置,放下一个数

time:46ms(69.17%)

mem:17.26MB(88.56%)


总结:

1.双指针:往往应用在直接修改数组的题目上,在编写程序时,需要思考清楚两个指针的动作逻辑,分析清楚即可;

2.nums[left], nums[right] = nums[right], nums[left]——这个语句可以同时交换list中的元素,不需要使用temp

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值