美文网首页
LeetCode - 283. 移动零 swift

LeetCode - 283. 移动零 swift

作者: huxq_coder | 来源:发表于2020-08-12 11:17 被阅读0次

    原题链接:
    https://leetcode-cn.com/problems/move-zeroes/

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

    示例:

    输入: [0,1,0,3,12]
    输出: [1,3,12,0,0]
    说明:

    必须在原数组上操作,不能拷贝额外的数组。
    尽量减少操作次数。

    算法

    /**
    简单粗暴的一种解题方法,类似于冒泡排序
    两次遍历。每次遍历前后元素比较,前一个为0,后一个不为0则交换,遍历完成之后,会有一个为0的元素到数组的最后一个位置,然后进行下一次遍历,直到所有元素遍历完成。所有为0的元素都放在数组最后。
     时间复杂度 O(n^2)
     空间复杂度 O(1)
     提交LeetCode时不通过,因为数据量太大时耗时太多
    */
    func moveZeroes(_ nums: inout [Int]) {
        for i in 0..<nums.count {
            for j in stride(from: i+1, to: nums.count, by: 1) {
                if nums[i] == 0 && nums[j] != 0 {
                    let temp = nums[i]
                    nums[i] = nums[j]
                    nums[j] = temp
                }
            }
        }
    }
    /**
     输入:[0,1,0,3,12]
     每次交换的结果:
     [1, 0, 0, 3, 12]
     [1, 0, 0, 3, 12]
     [1, 0, 0, 3, 12]
     [1, 0, 0, 3, 12]
     [1, 0, 0, 3, 12]
     [1, 3, 0, 0, 12]
     [1, 3, 0, 0, 12]
     [1, 3, 0, 0, 12]
     [1, 3, 12, 0, 0]
     [1, 3, 12, 0, 0]
     */
    
    /**
     时间复杂度O(n)
     空间复杂度O(1)
     快慢指针
     i : 快指针
     lastNonZeroIndex : 慢指针(最后一个非零指针)
     第一次遍历,向前移动所有的非零数字,慢指针之前都是非零,之后都是零
     第二次遍历,慢指针之后的数字赋值为零
     */
    func moveZeroes(_ nums: inout [Int]) {
        var lastNonZeroIndex = 0
        for i in 0..<nums.count {
            if nums[i] != 0 {
                // 向前移动非零数字
                nums[lastNonZeroIndex] = nums[i]
                // 最后非零指针向后移动一位
                lastNonZeroIndex = lastNonZeroIndex + 1
            }
        }
        // 以上遍历完成之后,lastNonZeroIndex之前的数字都是非零,之后的数字都是0
        // 再次遍历,将lastNonZeroIndex之后的元素全部赋值为0
        for i in lastNonZeroIndex..<nums.count {
            nums[i] = 0
        }
    }
    
    👆动画演示
    /**
     时间复杂度O(n)
     空间复杂度O(1)
     快慢指针
     进一步优化
     类似快速排序,将0作为中间的数字进行左右分割,等于0的元素放在右边,不等于0的元素放在左边。
     */
    func moveZeroes(_ nums: inout [Int]) {
        var lastNonZeroIndex = 0
        for i in 0..<nums.count {
            if nums[i] != 0 {
                // 直接进行交换
                let temp = nums[lastNonZeroIndex]
                nums[lastNonZeroIndex] = nums[i]
                nums[i] = temp
                // 交换也可以这么写
                //    (nums[i], nums[lastNonZeroIndex]) = (nums[lastNonZeroIndex], nums[i])
    
                lastNonZeroIndex = lastNonZeroIndex + 1
            }
        }
    }
    
    👆动画演示
    /**
     时间复杂度O(n)
     空间复杂度O(1)
     快慢指针
     参考了国际站的题解之后在上一个基础上再次优化
     */
    func moveZeroes(_ nums: inout [Int]) {
        // 过滤掉不需要处理的情况
        // 数组元素小于2个,直接返回
        guard nums.count > 1 else {
            return
        }
        var lastNonZeroIndex = 0
        for i in 0..<nums.count {
            if nums[i] != 0 {
                if i > lastNonZeroIndex {
                    // 通过以上 i > lastNonZeroIndex 避免了两个 i == lastNonZeroIndex 时的冗余操作
                    // 交换 改为 赋值,非零数字赋值到零数字的位置,之前非零的位置可以直接赋值为零(交换也是赋值为零,所以直接进行赋值零)
                    nums[lastNonZeroIndex] = nums[i]
                    nums[i] = 0
                }
                // 非零就后移一位
                lastNonZeroIndex += 1
            }
        }
    }
    
    var nums = [0,1,0,3,12]
    moveZeroes(&nums)
    
    

    以上算法的一步步优化参考了中文站和国际站上的一些题解。
    LeetCode上有一位同学的题解非常好,比官方的题解更容易理解。链接:https://leetcode-cn.com/problems/move-zeroes/solution/dong-hua-yan-shi-283yi-dong-ling-by-wang_ni_ma/
    以上的动画演示都是出自这位同学的题解,如有侵权,请联系删除。

    GitHub:https://github.com/huxq-coder/LeetCode
    欢迎star

    相关文章

      网友评论

          本文标题:LeetCode - 283. 移动零 swift

          本文链接:https://www.haomeiwen.com/subject/feypdktx.html