Start learning free

LESSON 265 OF 414 · HASH TABLE

Remove Duplicates From Array in Scala: O(n) with a HashSet

Practice O(n) Read the full explanation

Given an array of integers, return a new array containing only the unique values.

The resulting array can be in any order.

Example:

Input: [2, 3, 1, 1, 4, 3, -2, 1]
Output: [2, 3, 1, 4, -2]
			

Note:

Your algorithm should run in O(n) time and use O(n) extra space.


STEP 1 OF 3
    Ctrl + Enter to check

    SCALA · HASH TABLE

    Remove Duplicates From Array in Scala, explained

    Problem overview

    The method removeDuplicates receives an Array[Int] called nums and returns a new Array[Int] that holds each distinct value once. The result can be in any order.

    For Array(2, 3, 1, 1, 4, 3, -2, 1) the distinct values are 2, 3, 1, 4 and -2, so the result has five elements. The statement shows them as 2, 3, 1, 4, -2, but since any order is accepted, 4, 3, 2, 1, -2 or any other arrangement is just as valid.

    The lesson asks for O(n) time and O(n) extra space.

    Approach: let a hash set drop the repeats

    A set stores each value at most once. Inserting a value that is already present does nothing, so duplicates disappear without any extra work. A hash set also does an insertion in constant time on average, so adding all n numbers costs O(n). Once every number has been inserted, the set contains exactly the distinct values, and converting it to an array gives the answer.

    The price of this approach is order. A hash set arranges its elements by hash code, not by insertion order, so the result usually doesn't follow the order of the input. The statement allows that. If you needed the first occurrence of each value kept in input order, you would use a LinkedHashSet instead.

    Step by step

    1. Create an empty mutable hash set of Int named uniqueValues: scala.collection.mutable.HashSet[Int](). The default Set in Scala is immutable, so the mutable class is named with its full package.
    2. Loop over nums with for (value <- nums) and call uniqueValues.add(value) for each element. add returns false when the value is already in the set, so there is no need to check first.
    3. Convert and return. uniqueValues.toArray copies the set's elements into a new Array[Int], which is the return type the method needs.

    The solution in Scala

    class Solution {
        def removeDuplicates(nums: Array[Int]): Array[Int] = {
            val uniqueValues = scala.collection.mutable.HashSet[Int]()
            for (value <- nums) {
                uniqueValues.add(value)
            }
            return uniqueValues.toArray
        }
    }
    

    The Scala details worth a closer look:

    • The ignored result of add. The call returns a Boolean, and the loop throws it away. That is fine here, because the side effect on the set is what matters.
    • toArray builds a new array. The returned array is independent of the set and of nums, which is left unchanged. For a HashSet[Int] the element type is known, so the result is an Array[Int], as the method signature requires.
    • Order is not specified. The elements of the result come out in whatever order the hash set holds them, so don't rely on it. If you want a predictable order, sort the result with .sorted, which returns a new sorted array: for the example it gives 1, 2, 3, 4 and -2 in the order -2, 1, 2, 3, 4.
    • Shorter forms exist. nums.distinct returns the distinct values in first-seen order, and nums.toSet.toArray does the same job as the loop. The lesson writes the loop to practise the set.

    Complexity

    Time: O(n). There are n insertions, each constant time on average, and one final pass that copies at most n elements into the array.

    Space: O(n). The set holds up to n values when all of them are different, and the result array needs room for the same number.

    Edge cases and common mistakes

    • Empty array. The set stays empty and the result is an empty array.
    • All values equal. Array(5, 5, 5) gives an array with the single element 5.
    • No duplicates. The result has the same elements as the input, possibly in a different order.
    • Comparing with an expected array by position. Since the order isn't fixed, compare after sorting if you test it yourself. Also, == on two arrays compares references, not contents, so Array(1, 2) == Array(1, 2) is false. Convert both with toList before comparing.
    • Using the immutable Set. It has no add method that changes it in place, so the loop wouldn't do what you want.

    Testing

    • Array(2, 3, 1, 1, 4, 3, -2, 1) gives the values -2, 1, 2, 3, 4 once each, in some order.
    • Array(5, 5, 5) gives Array(5).
    • Array(1, 2, 3) gives the same three values.
    • Array() gives an empty array.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free