0

I have a task. I know this task is really easy but..

A non-empty zero-indexed array A consisting of N integers is given. A permutation is a sequence containing each element from 1 to N once, and only once. For example, array A such that:

  • A[0] = 4
  • A[1] = 1
  • A[2] = 3
  • A[3] = 2

is a permutation, but array A such that:

  • A[0] = 4
  • A[1] = 1
  • A[2] = 3

is not a permutation. The goal is to check whether array A is a permutation.

I implemented this solution, but I think this isn't the best solution.

def solution(A):
    # write your code in Python 2.6
    maxN = max(A)
    B = list(xrange(1,maxN+1))
    if sorted(A) == sorted(B):
        return 1
    else:
        return 0

Do you have any ideas how I should solve this problem?

Tim Peters
  • 67,464
  • 13
  • 126
  • 132
STK
  • 102
  • 4
  • 11
  • possible duplicate of [How to generate all permutations of a list in Python](http://stackoverflow.com/questions/104420/how-to-generate-all-permutations-of-a-list-in-python) – Dan Jan 08 '14 at 01:56

7 Answers7

3
def solution(A):
    N = len(A)
    return min(A) == 1 and max(A) == N and len(set(A)) == N

That takes (expected) time linear in N, so is expected to be faster than sorting. But it does rely on the stated assumption that all list entries are in fact integers. If they're not, then, for example,

>>> solution([1, 2, 4, 3.14159])
True
Tim Peters
  • 67,464
  • 13
  • 126
  • 132
  • I wonder how bad the runtime can actually get, since hash collisions are somewhat restricted by the fact that we know all elements are between 1 and n. – user2357112 Jan 08 '14 at 02:12
  • @user2357112, nothing in the problem statement says all input elements are between 1 and `n`. We're only told that the input array contains `N` integers. In any case, CPython's dicts (& sets) are guaranteed to have no collisions at all if storing a contiguous range of integers (although that's not guaranteed by the docs - it's a fact of the CPython implementation). – Tim Peters Jan 08 '14 at 02:15
  • We know all input elements are between 1 and n because we check that `min(A) == 1 and max(A) == N`. – user2357112 Jan 08 '14 at 02:16
  • Ah, OK. Then, as I said, there are no collisions at all, except on identical values. – Tim Peters Jan 08 '14 at 02:17
  • 1
    Collisions would have to occur while building the set, before it reaches full size. Elements can still land in the same bucket then. – user2357112 Jan 08 '14 at 02:21
  • Good point! Now try to find an example where you can actually measure a difference ;-) – Tim Peters Jan 08 '14 at 02:27
0

What about this?:

>>> def is_permutation(a, n):
        if len(a) != n: return False
        h = {}
        for i in a:
            if not 1 <= i <= n: return False
            if h.setdefault(i, False): return False
            h[i] = True
        return True

>>> is_permutation([1,4,2,3], 4)
True
>>> is_permutation([1,4,2,0], 4)
False
>>> is_permutation([1,4,2],4)
False
mshsayem
  • 17,557
  • 11
  • 61
  • 69
  • I'd use an n-length array for the flags, but other than that, the first solution looks good. The second doesn't work; `[2, 2, 2]` is not a permutation. – user2357112 Jan 08 '14 at 02:06
  • 1
    If you don't mind, please correct your syntax, `i<2 or i>n` looks really weird. I think that I'll look better with spaces. – pkacprzak Jan 08 '14 at 03:18
0

If both arrays should have all numbers from 1 to N you shouldn't sort them, all you need to do is make sure they actually have all the numbers.

so this is your algorithm (working solution soon):

  1. make sure the list is of size N, otherwise return false.
  2. generate list of N zeros (We will refer to it as zero-list)
  3. for each member (say it's value is m) of the list (both) increase the zero-list[m-1] by 1
  4. make sure all members of zero-list is 1

This is O(n) as opposed to O(nlogn) that you have right now.

What you are doing verifies that each member from 1 to N exists in the list you're given

#!/usr/bin/env python

def is_perm(l, n):
    # make sure initial criterias are met
    if len(l) != max(l) or len(l) != n:
        return False
    # make room for a list that verifies existence from 1 to N
    zero_list = [0 for i in l]
    # "mark" using the new list each member of the input list
    for i in l:
        try:
            zero_list[i-1] += 1
        except:
            return False

    # make sure all members have been "marked"
    for i in zero_list:
        if zero_list[i] != 1:
            return False

    # if all is good, the earth is saved
    return True

if "__main__" == __name__:
    print is_perm([1, 2, 3, 3], 4) # false
    print is_perm([1, 2, 4, 3], 4) # true
    print is_perm([1, 2, 4, 300000000000000], 4) # false
Reut Sharabani
  • 30,449
  • 6
  • 70
  • 88
0
def is_perm(lst):
    n = len(lst)
    if min(lst) != 1 or max(lst) != n:
        return False
    cnt = [1] * n
    for e in lst:
        cnt[e - 1] -= 1
    return not any(cnt)

It has a worst case complexity O(n) which is of course optimal.

pkacprzak
  • 5,537
  • 1
  • 17
  • 37
0

Just check if all elements are present ...

In [36]: all(map(lambda p: p in [1,4,3,2], range(1,5)))
Out[36]: True
In [37]: all(map(lambda p: p in [1,4,3,2444], range(1,5)))
Out[37]: False
In [38]: all(map(lambda p: p in [1,4,3], range(1,5)))
Out[38]: False
ssm
  • 5,277
  • 1
  • 24
  • 42
  • 1
    it has a quadratic complexity – pkacprzak Jan 08 '14 at 04:00
  • One can just use `imap()` instead of `map()` which returns a lazy iterator, and `all()` is lazy anyway, so we should be able to get much better than the quadratic complexity I think. No need to expressedly code that in these days with lazy evaluation becoming very common in Python. Also makes for code relatively easy to read. – ssm Jan 08 '14 at 06:48
0

So I found solution which works great:

def solution(A):
  A.sort(reverse=True)
  return 1 if A[0] == len(A) and len(set(A)) == len(A) else 0
STK
  • 102
  • 4
  • 11
0

Here is fastest way:

def solution(A):
    '''
    >>> solution([4,1,3,2])
    1
    >>> solution([2,3])
    0
    '''
    suma = sum(A)
    N = len(A)
    if (N*(N+1)/2)!=suma:
        return 0

    return 1
Farshid Ashouri
  • 16,143
  • 7
  • 52
  • 66