The problem: We are doing a permutation check. Given a list A
with n
elements and the task is to determine if A
is a permutation of natural numbers from 1 to n
.
For example
[4,2,3,1]
is a permutation since all element of the list are in the list [1..n] where n=4
.
[4,1,2]
is not a permutation since the 2 is missing.
Expected output
An efficient function that returns 1 if A is a permutation and 0 otherwise.
Restrictions:
- 1 <= n <= 100000
- Elements of A are in the range [1..1,000,000,000]
- Be efficient
My Solutions
First Attempt
At first glance I figured easy, just check the sum. The sum of natural numbers can be found using a simple formula sum = n(n+1) / 2 so my first attempt
function solution(A){ const expectedSum = (n * (n+1)) / 2 const actualSum = A.reduce((sum, value)=> sum + value, 0) return actualSum === expectedSum ? 1 : 0 }
This is efficient but has one tiny problem. Testing failed because of arrays like this [1,1,1,7]
. Notice our requirements didn’t say the numbers didn’t repeat, it was a bad assumption on my part.
Second attempt
My next thought was to convert A
into a set to get rid of any duplicates since if there were any then it wasn’t a permutation. The next step would be to check if all numbers from 1 to n existed in the set and give up as soon as we failed to find one. Something like this…
function solution(A){ const aSet = new Set(A) for(let i = 1;i <= A.length; i++) { if(!aSet.has(i)){ return 0 } } return 1 }
But first I decided to test out a thought. What happens if we check the sum of the set against the expected sum? Apparently we find an over sight in the tests that check solutions.
function solution(A){ const aSet = new Set(A) const n = A.length const expectedSum = (n * (n+1)) / 2 const actualSum = Array.from(aSet).reduce((sum, value)=> sum + value, 0) return actualSum === expectedSum ? 1 : 0 }
This isn’t supposed to work because of arrays like [1, 2, 1, 7]
but to my surprise, it passed all the tests brilliantly.
Go figure.
There is an easy fix for the bug however, just check set
size against list
size
if (aSet.size !== n){ return 0 }
That’s all I have for today. If you found this interesting or have a better way why not leave me a comment, or Follow @phoexer on Twitter.