Search code examples
arraysswiftcomparereduce

Find the missing element in a given permutation


First, a bit of background:

I'm working on one of the Codility lessons, and, even though this is easy to solve, logistically, it is less than easy to solve, performance-wise.

I've been able to boil it down to just this:

public func solution(_ A : inout [Int]) -> Int {
    let B = A   // Assigning it to a local speeds it up.
    return Array<Int>(Set(B)).sorted(by: {$0<$1}).reduce(0) { ($1 == $0 + 1) ? $1 : $0 } + 1
}

However, this is just a WEE bit too slow. I guess that the main reason is that the reduce goes through ALL elements of an array, even though the answer may be early. I may not be able to speed it up.

But I'd like to try. The part that I'm looking at is this:

.reduce(0) { ($1 == $0 + 1) ? $1 : $0 }

I'm wondering if I can make that comparison more efficient.

I have to check if $1 is equal to $0 + 1. I can't avoid that comparison.

The ternary operator is not actually faster than an if clause, but it looks cooler ;).

Is there a higher-performance way to compare two positive integers for equivalence than the basic "==" operator?

BTW: This is not a "do my homework for me" question. It's pretty legit, and these Codility lessons don't give you credit or anything. They are just a fun exercise. I want to know how to do this, as I'm sure I'll need it in the future.


Solution

  • Using the solution suggested by @TNguyen in comments, below piece of code got 100% on both correctness and performance.

    You just need to generate the correct Array, containing each Integer in the range [1..(N + 1)] by calling Array(1...A.count+1). Then you sum its elements using reduce(0,+) and finally substract the sum of the elements of the input array A. The difference between the two sums gives the missing element.

    public func solution(_ A : inout [Int]) -> Int {
        return Array(1...A.count+1).reduce(0,+)-A.reduce(0,+)
    }
    

    An even faster solution is to use the mathematical formula1+2+...+n=n(n-1)/2 for the first sum.

    public func solution(_ A : inout [Int]) -> Int {
        return (A.count+1)*(A.count+2)/2-A.reduce(0,+)
    }