Reputation: 7764
Im trying to solve below problem in scala
Input:[1,0,44,55,0,43,78,99]
output:[1,44,55,43,78,99,0,0]
here is what i have tried
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
}
output :[0,0,1,44,55,78,99,43]
not expected output
Im looking for o(n) time complexity and O(1) space complexity solution
This is a leetcode problem https://leetcode.com/problems/move-zeroes/
Upvotes: 2
Views: 169
Reputation: 1159
You can find all the immutable, functional, "true Scala" way of doing it in the above answers. But, considering the O(N) time-complexity and O(1) space complexity nothing beats a mutable, efficient, in-place algorithm!
Here is the implementation with Scala's array using foldLeft
:
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 }
No extra space due to collection creation (not even .toList
/.toArray
) and no sorting.
Upvotes: 0
Reputation: 4024
Functional and immutable solution, also very simple to understand:
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
}
Time complexity: O(n)
: Fixed number of iterations over the sequence.
Space complexity: O(n)
: removeZeros
, zeroSuffix
and the output line may consume up to n
space, so complexity is O(n)
.
Upvotes: 0
Reputation: 1678
This is a pure FP solution with O(n) time complexity and O(1) space complexity.
Unlike any of the other solutions so far, it can work for very large input that doesn't fit in memory:
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)
}
Upvotes: 1
Reputation: 7764
i have rewritten my code with while loop it seems to work, lemme know if there is more elegant solution which satisfies linear time complexity and constant space complexity
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
}
Upvotes: 2
Reputation: 142448
You can try something like that:
nums.zipWithIndex
.sortBy(t => if (t._1 == 0) Int.MaxValue else t._2)
.map(_._1)
zipWithIndex
will map your collection into sequence of tuples of element value and it's index (i.e. [(1, 0), (0, 21), (44, 2)]
for start of your example array)
sortBy
will perform the ordering by either index of element or Int.MaxValue
map
will return map to the original element.
Upvotes: 2