将零移动到数组的末尾

时间:2020-07-11 19:35:17

标签: scala

我正在尝试解决Scala中的以下问题

Input:[1,0,44,55,0,43,78,99]
output:[1,44,55,43,78,99,0,0]

这是我尝试过的

def moveZeros(nums:Array[Int]): Array[Int] ={
    for(i<-0 until nums.length ; j<-0 until nums.length){
      if(nums(j)!=0)
      {
        var temp:Int = nums(i)
        nums(i)=nums(j)
        nums(j)=temp
      }

    }
    nums
  }

输出:[0,0,1,44,55,78,99,43]

非预期输出

我正在寻找o(n)时间复杂度和O(1)空间复杂度解决方案

这是一个leetcode问题 https://leetcode.com/problems/move-zeroes/

5 个答案:

答案 0 :(得分:2)

您可以尝试以下方法:

nums.zipWithIndex
   .sortBy(t => if (t._1 == 0) Int.MaxValue else t._2)
   .map(_._1)

zipWithIndex会将您的集合映射到元素值的元组序列及其索引(即[(1, 0), (0, 21), (44, 2)]用于示例数组的开始)

sortBy将根据元素的索引或Int.MaxValue

进行排序

map将返回映射到原始元素。

答案 1 :(得分:2)

我用while循环重写了我的代码,它似乎可以正常工作,让我知道是否有更优雅的解决方案可以满足线性时间复杂度和恒定空间复杂度

  def moveZeros(nums: Array[Int]): Array[Int] = {
    var i = 0
    var j = 0
    while ( {
      i < nums.length && j < nums.length
    }) {
      if (nums(j) != 0) {
        val tmp = nums(i)
        nums(i)=nums(j)
        nums(j) = tmp
        i+=1
      }

      j += 1
    }
    nums

  }

答案 2 :(得分:1)

这是具有O(n)时间复杂度和O(1)空间复杂度的纯FP解决方案。

与迄今为止的任何其他解决方案不同,它可以用于内存中无法容纳的非常大的输入:

object MoveZeros extends App {
  def moveZerosToEnd(input: Iterator[Int]): Iterator[Int] = {
    val endOfInputSignal = None
    val iteratorWithEndSignal: Iterator[Option[Int]] =
      input.map(Some(_)) ++ Iterator.single(endOfInputSignal)
    iteratorWithEndSignal.scanLeft((0, Iterator.empty[Int])) {
      case ((zerosCounter, _), value) => value match {
        case Some(value) =>
          if (value == 0)
            // Count zero and drop it
            (zerosCounter + 1, Iterator.empty)
          else
            (zerosCounter, Iterator.single(value))
        case None =>
          // Add counted zeros to the end
          (zerosCounter, Iterator.fill(zerosCounter)(0))
      }
    }.flatMap(_._2)
  }
  val input = List(1,0,44,55,0,43,78,99)
  val expected = List(1,44,55,43,78,99,0,0)
  val res = moveZerosToEnd(input.iterator)
    .toList // To list only for easy testing
  assert(res == expected)
  println(res)
}

答案 3 :(得分:0)

功能不变的解决方案,也很容易理解:

def moveZerosToEnd(input: Seq[Int]): Seq[Int] = {
    val ZERO = 0
    val zeroCount = input.count(_==ZERO)
    val removeZeros = input.filter(_!=ZERO)
    val zeroSuffix = Seq.fill(zeroCount)(ZERO)
    removeZeros ++ zeroSuffix
}  

enter image description here

时间复杂度:O(n) :固定顺序的迭代次数。
空间复杂度:O(n) removeZeroszeroSuffix,并且输出线可能消耗多达n个空间,因此复杂度为O(n)

答案 4 :(得分:0)

您可以在上述答案中找到所有不变的,功能性的“真正的Scala”方法。但是,考虑到O(N)的时间复杂度和O(1)的空间复杂度,没有什么比可变,高效,就地算法更出色了!

以下是使用foldLeft的Scala数组的实现:

val arr = Array(1, 0, 44, 55, 0, 43, 78, 99)
val lastNonZero = arr.foldLeft(0) { 
  (zeros, elem) => if (elem != 0) { arr(zeros) = elem; zeros+1 } else zeros
}

(lastNonZero until arr.length).foreach{ i => arr(i) = 0 }

由于创建了馆藏(甚至没有.toList / .toArray)也没有多余的空间,也没有排序。

enter image description here