将零移动到数组编程练习结束的性能

时间:2019-02-25 17:11:00

标签: arrays swift algorithm performance

我想知道为什么我对这个LeetCode“移动零点”问题的解决方案比大多数其他提交方案都慢。有没有更好的方法来解决这个问题以使其更快?

问题如下:

  

给出一个数组onChange,编写一个函数,将所有0移到其末尾,同时保持非零元素的相对顺序。您必须就地执行此操作,而不需要复制阵列。

     

示例:

     

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

     

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

这是我的解决方案:

nums

LeetCode提供了这些统计信息:

  

运行时间:52毫秒,比“移动零点”的Swift在线提交的 40.50%快。
  内存使用量:19.4 MB,不到“移动零点”的Swift在线提交的13.33%。

编辑1:

如果我按照以下方法处理问题,它不会在结尾处移动零,

enter image description here

编辑2:

enter image description here

7 个答案:

答案 0 :(得分:2)

据我所见,可能其他提交者正在这样做

  • 检查并计数字符串中的0'
  • 删除0's
  • 替换字符串末尾的0'

毫无疑问,这是一种合乎逻辑的方法,但是我想说,您只是选择挑战的基本需求并坚持下去。

答案 1 :(得分:1)

我个人会使用:

input = input.filter { $0 != 0 } + input.filter { $0 == 0 }

enter image description here

可以简化为一遍:

let nonZeros = input.filter { $0 != 0 }
input = nonZeros + Array(repeating: 0, count: input.count - nonZeros.count)

enter image description here

编辑:不创建新数组的最简单版本是气泡排序的某些原始版本,例如:

var numZeros = 0

// iterate array from start to end
for (offset, element) in input.enumerated() {
    if element == 0 {
        // count every zero
        numZeros += 1
    } else if numZeros > 0 {
        // move every non-zero element left
        input[offset - numZeros] = element    
        // replace with zero
        input[offset] = 0
    }
}

enter image description here

答案 2 :(得分:1)

使用removeAll变异方法的Swift 4.2或更高版本:

更改输入:

class Solution {
    func moveZeroes(_ nums: inout [Int]) {
        var counter = 0
        nums.removeAll {
            if $0 == 0 {
                counter += 1
                return true
            }
            return false
        }
        nums += repeatElement(0, count: counter)
    }
}

与Swift 4.1或更早版本相似的方法

func moveZeroes(_ nums: inout [Int]) {
    var counter = 0
    nums.indices.reversed().forEach {
        if nums[$0] == 0 {
            counter += 1
            nums.remove(at: $0)
        }
    }
    nums += repeatElement(0, count: counter)
}

var input = [0,1,0,3,12]
moveZeroes(&input)
input   // [1, 3, 12, 0, 0]

非变异方法:

func moveZeroes(_ nums: [Int]) -> [Int] {
    var counter = 0
    return nums.filter {
        if $0 == 0 { counter += 1 }
        return $0 != 0
    } + repeatElement(0, count: counter)
}

let  input = [0,1,0,3,12]

let zerosMoved = moveZeroes(input)
zerosMoved   // [1, 3, 12, 0, 0]

答案 3 :(得分:1)

另一种方法是半稳定分区算法。好处是可以交换项目,而不是将其删除并插入/添加。

半稳定表示保留分割点左侧的顺序。

extension Array {

    mutating func halfStablePartition(indexes : IndexSet) { // code is O(n)
        guard var i = indexes.first, i < count else { return }
        var j = index(after: i)
        var k = indexes.integerGreaterThan(i) ?? endIndex
        while j != endIndex {
            if k != j { swapAt(i, j); formIndex(after: &i) }
            else { k = indexes.integerGreaterThan(k) ?? endIndex }
            formIndex(after: &j)
        }
    }
}

var input = [0,1,0,3,12]

let indices = IndexSet(input.indices.filter{input[$0] == 0})
input.halfStablePartition(indexes: indices)

答案 4 :(得分:1)

这是适合您的36ms就地解决方案:

class Solution {
    func moveZeroes(_ nums: inout [Int]) {

        if nums.count < 2 {
            return
        }

        var j = 0

        while j < nums.count, nums[j] != 0 {
            j += 1
        }

        if j < nums.count - 1 {
            for i in j+1..<nums.count {
                if nums[i] != 0 {
                    nums.swapAt(i, j)
                    j += 1
                }
            }
        }
    }
}

36

答案 5 :(得分:0)

一种快速的解决方案是将非零元素向左移动直到遇到的零数量:

func moveZeroes(_ nums: inout [Int]) {
    var offset = 0
    for i in 0..<nums.count {
        if nums[i] == 0 { offset += 1 }
        else { nums.swapAt(i, i-offset) }
    }
}

此解决方案正好需要N步,并且在每一步我们都执行加法或交换,这两个步骤都非常快。

另一方面,您的解决方案需要两次迭代,导致2 * N步,这就是为什么它比其他解决方案要慢的原因。

答案 6 :(得分:0)

用于修改数组并将其保留:

O(n)表示时间复杂度

O(1)表示空间复杂度

我很想念这个。交换不为零的元素的最干净方法:

func moveZeroes(_ nums: inout [Int]) {
    // amount of swaps, will be used a as reference for next swap index
    var j = 0 
    
    for (i, e) in nums.enumerated() {
        if e != 0 {
            nums.swapAt(j, i)
            j += 1
        }
    }
    
}