Trova il primo elemento duplicato


39

Dato un array a che contiene solo numeri nell'intervallo compreso tra 1 e a. Lunghezza, trova il primo numero duplicato per il quale la seconda occorrenza ha l'indice minimo. In altre parole, se sono presenti più di 1 numeri duplicati, restituisce il numero per il quale la seconda occorrenza ha un indice più piccolo rispetto alla seconda occorrenza dell'altro numero. Se non ci sono tali elementi, il programma / funzione potrebbe comportare un comportamento indefinito.

Esempio:

Per a = [2, 3, 3, 1, 5, 2], l'output dovrebbe essere firstDuplicate(a) = 3.

Ci sono 2 duplicati: numeri 2 e 3. La seconda occorrenza di 3 ha un indice più piccolo rispetto alla seconda occorrenza di 2, quindi la risposta è 3.

Per a = [2, 4, 3, 5, 1], l'output dovrebbe essere firstDuplicate(a) = -1.

Questo è , quindi vince la risposta più breve in byte.

BONUS: Riesci a risolverlo in O (n) complessità temporale e O (1) complessità spaziale aggiuntiva?


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Martin Ender,

Risposte:


15

Python 2 , 34 byte

O (n 2 ) tempo, O (n) spazio

Salvato 3 byte grazie a @vaultah e altri 3 da @xnor!

lambda l:l[map(l.remove,set(l))<0]

Provalo online!


1
Sembra che lambda l:l[map(l.remove,set(l))<0]funzioni, anche se l'ordine di valutazione è strano.
xnor

Questo non ritorna -1quando non vengono trovati duplicati senza il 'codice piè di pagina', quel codice non conta per i byte? Sono nuovo nel codice golf, scusate se è una domanda di base!
Chris_Rands

@Chris_Rands Sotto la domanda che il musicista ha posto se l'eccezione è ok invece di -1 e OP ha detto che è ok e la risposta del musicista genera l'eccezione.
Liefde:

Mi ci è voluto un po 'per capire. Ben fatto. Ottenere il 0 ° elemento di l usando il condizionale dopo averlo modificato è davvero intelligente.
Thoth19

Python garantisce la complessità temporale e spaziale delle funzioni di libreria standard come set.remove?
Draconis,

11

JavaScript (ES6), 47 36 31 25 byte

6 byte salvati grazie a ThePirateBay

Restituisce undefinedse non esiste alcuna soluzione.

Complessità temporale: O (n) :-)
Complessità spaziale: O (n) :-(

a=>a.find(c=>!(a[-c]^=1))

Come?

Teniamo traccia dei valori già rilevati salvandoli come nuove proprietà dell'array originale a utilizzando numeri negativi. In questo modo, non possono interferire con le voci originali.

dimostrazione


25 byte:a=>a.find(c=>!(a[-c]^=1))

@ThePirateBay Oh, certo. Grazie!
Arnauld,

Si noti che gli oggetti in JavaScript potrebbero non essere implementati come tabella hash. La complessità temporale dell'accesso alle chiavi di alcuni oggetti potrebbe non essere O (1).
TSH

6

Mathematica, 24 byte

#/.{h=___,a_,h,a_,h}:>a&

La capacità di abbinamento dei modelli di Mathematica è davvero fantastica!

Restituisce l'originale Listper input non valido.

Spiegazione

#/.

Nell'input, sostituire ...

{h=___,a_,h,a_,h}

A Listcon un elemento duplicato, con 0 o più elementi prima, tra e dopo i duplicati ...

... :>a

Con l'elemento duplicato.


6

Gelatina , 5 byte

Ṛœ-QṪ

Provalo online!

Come funziona

Ṛœ-QṪ  Main link. Argument: A (array)

Ṛ      Yield A, reversed.
   Q   Unique; yield A, deduplicated.
 œ-    Perform multiset subtraction.
       This removes the rightmost occurrence of each unique element from reversed
       A, which corresponds to the leftmost occurrence in A.
    Ṫ  Take; take the rightmost remaining element, i.e., the first duplicate of A.

œ-rimuove le occorrenze più giuste? TIL
Erik the Outgolfer

Questo non sembra restituire -1senza duplicati. Lanciare un'eccezione va bene come per OP ma non sono sicuro che lo 0sia anche se non è nel range.
Erik the Outgolfer,


4

Gelatina , 6 byte

xŒQ¬$Ḣ

Provalo online!

Restituisce il primo duplicato o 0 se non ci sono duplicati.

Spiegazione

xŒQ¬$Ḣ  Input: array M
    $   Operate on M
 ŒQ       Distinct sieve - Returns a boolean mask where an index is truthy
          for the first occurrence of an element
   ¬      Logical NOT
x       Copy each value in M that many times
     Ḣ  Head

E 'Golfier ad utilizzare l'indicizzazione in questo modo: ŒQi0ị.
Erik the Outgolfer,

@EriktheOutgolfer Se non ci sono duplicati, i0restituirebbe 0, dove indicizzerebbe e restituirebbe l'ultimo valore dell'input invece di 0.
miglia

4

Japt , 7 byte

æ@bX ¦Y

Provalo online!

Spiegazione

 æ@   bX ¦ Y
UæXY{UbX !=Y}  Ungolfed
               Implicit: U = input array
UæXY{       }  Return the first item X (at index Y) in U where
     UbX         the first index of X in U
         !=Y     is not equal to Y.
               In other words, find the first item which has already occured.
               Implicit: output result of last expression

In alternativa:

æ@¯Y øX

Provalo online!

Spiegazione

 æ@   ¯ Y øX
UæXY{Us0Y øX}  Ungolfed
               Implicit: U = input array
UæXY{       }  Return the first item X (at index Y) in U where
     Us0Y        the first Y items of U (literally U.slice(0, Y))
          øX     contains X.
               In other words, find the first item which has already occured.
               Implicit: output result of last expression

4

Pyth, 5 byte

h.-Q{

Suite di test

Rimuovere da Q la prima apparizione di ogni elemento in Q, quindi restituire il primo elemento.


@LuisMendo Ok grazie. Scusate se ho creato confusione, dovrei imparare a leggere ...
Mr. Xcoder,

@ Mr.Xcoder No, è colpa dell'OP. Tali informazioni dovrebbero essere contenute nel testo della sfida, ma solo in un commento
Luis Mendo,

4

Dyalog APL, 27 24 20 19 13 12 11 byte

⊢⊃⍨0⍳⍨⊢=⍴↑∪

Ora modificato per non dipendere da v16! Provalo online!

Come? (Con ingresso N )

  • ⊢⊃⍨...- N in questo indice:
    • ⍴↑∪- N con duplicati rimossi, imbottitura a destra 0per adattarsi a N
    • ⊢= - Uguaglianza saggia con N
    • 0⍳⍨- Indice del primo 0. `

non importa, ho letto male la domanda. non sufficienti casi di test ...
Uriel,

Scusami per averti ingannato, ho anche letto male la domanda.
miglia

A me sembrano 36 byte.
Adám,

Oh dio, Iota Underbar non è dentro ⎕AV, vero?
Zacharý,

@ Zacharý A destra, Classic lo traduce ⎕U2378 durante il caricamento. Provalo online!
Adám,

3

Python 3 , 94 92 byte

O (n) tempo e O (1) memoria aggiuntiva.

def f(a):
 r=-1
 for i in range(len(a)):t=abs(a[i])-1;r=[r,i+1][a[t]<0>r];a[t]*=-1
 return r

Provalo online!

Fonte dell'algoritmo .

Spiegazione

L'idea di base dell'algoritmo è quella di scorrere ogni elemento da sinistra a destra, tenere traccia dei numeri che sono apparsi e restituire il numero al raggiungimento di un numero che è già apparso e restituire -1 dopo aver attraversato ciascun elemento.

Tuttavia, utilizza un modo intelligente per memorizzare i numeri che sono apparsi senza usare memoria aggiuntiva: per memorizzarli come segno dell'elemento indicizzato dal numero. Ad esempio, posso rappresentare il fatto che 2e 3è già apparso avendo a[2]e a[3]negativo, se la matrice è 1-indicizzato.


Cosa farebbe per idove un [i]> n?
Downgoat,

@Downgoat leggi di nuovo la domanda.
Leaky Nun,

La domanda dice 1a.length ma per un [i] = a.length questo non andrebbe oltre i limiti?
Downgoat,

@Downgoatt=abs(a[i])-1=a.length-1
Leaky Nun


3

Perl 6 , 13 byte

*.repeated[0]

Provalo


Spiegazione

  • La *si trova in una posizione Term così l'intera dichiarazione è un WhateverCode lambda.

  • Il .repeatedè un metodo che comporta ogni valore tranne che per la prima volta è stato visto ogni valore.

    say [2, 3, 3, 3, 1, 5, 2, 3].repeated.perl; # (3, 3, 2, 3).Seq
    #   (      3, 3,       2, 3).Seq
  • [0]restituisce semplicemente il primo valore nel Seq .
    Se non è presente alcun valore, viene restituito Nil .
    ( Nil è la base dei tipi di errore e tutti i tipi hanno il loro valore indefinito, quindi Nil diverso da un valore indefinito nella maggior parte delle altre lingue)


Si noti che poiché l' implementazione di.repeated genera un Seq ciò significa che non inizia a fare alcun lavoro fino a quando non si richiede un valore e fa solo abbastanza lavoro per generare ciò che si richiede.
Quindi sarebbe facile sostenere che ciò ha nel peggiore dei casi O (n)  complessità temporale, e nella migliore delle ipotesi O (2)  complessità temporale se il secondo valore è una ripetizione del primo.
Probabilmente si può dire simile della complessità della memoria.


3

APL (Dyalog) , 20 byte

n/⍨(,≢∪)¨,\n←⎕,2⍴¯1

Provalo online!

2⍴¯1 negativo uno r eshaped in una lista di lunghezza doppietta

⎕, ottenere input (mnemonic: console box) e anteporre a quello

n← memorizzalo in n

,\ prefissi di n (lett. concatenazione cumulativa)

(...  applica la seguente funzione tacita a ciascun prefisso

, [is] the ravel (garantisce solo che il prefisso sia un elenco)

 diverso da

 gli elementi univoci [?] (ovvero il prefisso ha duplicati?)

n/⍨ usalo per filtrare n (rimuove tutti gli elementi fino al primo per cui è stato trovato un duplicato)

 scegli il primo elemento da quello


Wow, you got beat three times. Still, +1. And can you add an explanation of how this works?
Zacharý

@Zacharý Apparently I just needed to get the ball rolling. Here you go.
Adám

@Zacharý Eventually, I managed to beat them all.
Adám

3

APL (Dyalog), 11 bytes

As per the new rules, throws an error if no duplicates exist.

⊢⊃⍨⍬⍴⍳∘≢~⍳⍨

Try it online!

⍳⍨ the indices of the first occurrence of each element

~ removed from

⍳∘≢ of all the indices

⍬⍴ reshape that into a scalar (gives zero if no data is available)

⊃⍨ use that to pick from (gives error on zero)

 the argument


Well, yeah, when the rules are changed, of course you can beat them all!
Zacharý

Well, I tied you.
Zacharý

3

APL, 15

{⊃⍵[(⍳⍴⍵)~⍵⍳⍵]}

Seems like we can return 0 instead of -1 when there are no duplicates, (thanks Adám for the comment). So 3 bytes less.

A bit of description:

⍵⍳⍵         search the argument in itself: returns for  each element the index of it's first occurrence
(⍳⍴⍵)~⍵⍳⍵   create a list of all indexes, remove those found in ⍵⍳⍵; i.e. remove all first elements
⊃⍵[...]     of all remaining elements, take the first. If the array is empty, APL returns zero

For reference, old solution added -1 to the list at the end, so if the list ended up empty, it would contain -1 instead and the first element would be -1.

{⊃⍵[(⍳⍴⍵)~⍵⍳⍵],¯1}

Try it on tryapl.org


You may return a zero instead of ¯1, so {⊃⍵[(⍳⍴⍵)~⍵⍳⍵]} should do.
Adám

3

Retina, 26 24 bytes

1!`\b(\d+)\b(?<=\b\1 .*)

Try it online! Explanation: \b(\d+)\b matches each number in turn, and then the lookbehind looks to see whether the number is a duplicate; if it is the 1st match is ! output, rather than the count of matches. Unfortunately putting the lookbehind first doesn't seem to work, otherwise it would save several bytes. Edit: Added 7 bytes to comply with the -1 return value on no match. Saved 2 bytes thanks to @MartinEnder.


2
For the record, the lookaround won't backtrack. This prevents this from working if you try to put it before. I've made this mistake many times, and Martin always corrects me.
FryAmTheEggman

I got 30 bytes by using a lookahead instead of a lookbehind. Also, the rules now say you don't need to return -1.
Value Ink

@ValueInk But the correct answer for that test case is 3...
Neil

OH. I misread the challenge, whoops
Value Ink

2

MATL, 8 bytes

&=Rsqf1)

Gives an error (without output) if no duplicate exists.

Try at MATL Online!

Explanation

&=   % Implict input. Matrix of all pairwise equality comparisons
R    % Keep the upper triangular part (i.e. set lower part to false)
s    % Sum of each column
q    % Subtract 1
f    % Indices of nonzero values
1)   % Get first. Gives an error is there is none. Implictly display

2

R, 34 bytes

c((x=scan())[duplicated(x)],-1)[1]

Cut a few characters off the answer from @djhurio, don't have enough reputation to comment though.


oh...I didn't see this answer; this is good for the prior spec when missing values required -1 but with the new spec, I managed to golf it down even more. This is still solid and it's a different approach from the way he did it, so I'll give you a +1!
Giuseppe

2

J, 17 16 bytes

(*/{_1,~i.&0)@~:

How?

(*/{_1,~i.&0)@~:

             @~: returns the nub sieve which is a vector with 1 for the first occurrence of an element in the argument and 0 otherwise

        i.&0     returns the first index of duplication

    _1,~         appends _1 to the index

 */              returns 0 with duplicates (product across nub sieve)

     {           select _1 if no duplicates, otherwise return the index

2

R, 28 bytes

(x=scan())[duplicated(x)][1]

Try it online!


I think you can now return NA for missing values since the spec has changed; so (x=scan())[duplicated(x)][1] is perfectly valid.
Giuseppe

2

J, 12 bytes

,&_1{~~:i.0:

Try it online!

Explanation

,&_1{~~:i.0:  Input: array M
      ~:      Nub-sieve
          0:  The constant 0
        i.    Find the index of the first occurrence of 0 (the first duplicate)
,&_1          Append -1 to M
    {~        Select the value from the previous at the index of the first duplicate

2

Dyalog APL Classic, 18 chars

Only works in ⎕IO←0.

     w[⊃(⍳∘≢~⍳⍨)w←¯1,⎕]

Remove from the list of indices of the elements of the argument with a prepended "-1" the list indices of its nub and then pick the first of what's left. If after the removal there only remains an empty vector, its first element is by definition 0 which is used to index the extended argument producing the desired -1.


Um... what's with the random leading spaces? +1 for outgolfing me by one byte.
Zacharý

You may throw an error instead of returning ¯1, so you can remove ¯1, and use ⎕IO←1.
Adám


2

Java (OpenJDK 8), 65 117 109 bytes

Previous 65 byte solution:

r->{for(int a,b=0,z,i=0;;b=a)if((a=b|1<<(z=r[i++]))==b)return z;}

New solution. 19 bytes are included for import java.math.*;

-8 bytes thanks to @Nevay

r->{int z,i=0;for(BigInteger c=BigInteger.ZERO;c.min(c=c.setBit(z=r[i++]))!=c;);return z;}

Try it online!

Edit

The algorithm in my original program was fine, but the static size of the datatype used meant that it broke fairly quickly once the size went above a certain threshold.

I have changed the datatype used in the calculation to increase the memory limit of the program to accommodate this (using BigInteger for arbitrary precision instead of int or long). However, this makes it debatable whether or not this counts as O(1) space complexity.

I will leave my explanation below intact, but I wish to add that I now believe it is impossible to achieve O(1) space complexity without making some assumptions.

Proof

Define N as an integer such that 2 <= N .

Let S be a list representing a series of random integers [x{1}, ..., x{N}], where x{i} has the constraint 1 <= x{i} <= N.

The time complexity (in Big-O notation) required to iterate through this list exactly once per element is O(n)

The challenge given is to find the first duplicated value in the list. More specifically, we are searching for the first value in S that is a duplicate of a previous item on the list.

Let p and q be the positions of two elements in the list such that p < q and x{p} == x{q}. Our challenge becomes finding the smallest q that satisfies those conditions.

The obvious approach to this problem is to iterate through S and check if our x{i} exists in another list T: If x{i} does not exist in T, we store it in T. If x{i} does exist in T, it is the first duplicate value and therefore the smallest q, and as such we return it. This space efficiency is O(n).

In order to achieve O(1) space complexity while maintaining O(n) time complexity, we have to store unique information about each object in the list in a finite amount of space. Because of this, the only way any algorithm could perform at O(1) space complexity is if: 1. N is given an upper bound corresponding to the memory required to store the maximum number of possible values for a particular finite datatype. 2. The re-assignment of a single immutable variable is not counted against the complexity, only the number of variables (a list being multiple variables). 3. (Based on other answers) The list is (or at least, the elements of the list are) mutable, and the datatype of the list is preset as a signed integer, allowing for changes to be made to elements further in the list without using additional memory.

1 and 3 both require assumptions and specifications about the datatype, while 2 requires that only the number of variables be considered for the calculation of space complexity, rather than the size of those variables. If none of these assumptions are accepted, it would be impossible to achieve both O(n) time complexity and O(1) space complexity.

Explanation

Whoo boy, this one took an embarrassingly long time to think up a bit of brain power.

So, going for the bonus is difficult. We need both to operate over the entire list exactly once and track which values we've already iterated over without additional space complexity.

Bit manipulation solves those problems. We initialize our O(1) 'storage', a pair of integers, then iterate through the list, OR-ing the ith bit in our first integer and storing that result to the second.

For instance, if we have 1101, and we perform an OR operation with 10, we get 1111. If we do another OR with 10, we still have 1101.

Ergo, once we perform the OR operation and end up with the same number, we've found our duplicate. No duplicates in the array causes the program to run over and throw an exception.


Also, your second test includes the number 100, but thats impossible since the array itself is only 5 long
SchoolBoy

Also, this fails since an int doesn't have enough storage.
SchoolBoy

@SchoolBoy Good catch. My only problem is that there doesn't seem to be any upper limit on the size of the array, so I can't realistically change my code to solve memory issues.
Xanderhall

@Xanderhall True, but i feel like 32 (or if you use a long, 64) numbers is too little :p. Either way, imposing a limit on the input, and then allocating the maximum memory needed and calling it O(1) memory is just a cheat. It is still O(n) since if the size of the input increased, so would this upper bound to the memory. Which is also why I think it is impossible to create an O(n) O(1) algorithm
SchoolBoy

@Xanderhall P.S. I'm getting close to your 65, I'm at 67 bytes :p
SchoolBoy

2

PHP, 56 44 38 32 bytes

for(;!${$argv[++$x]}++;);echo$x;

Run like this:

php -nr 'for(;!${$argv[++$x]}++;);echo$x;' -- 2 3 3 1 5 2;echo
> 3

Explanation

for(
  ;
  !${                 // Loop until current value as a variable is truthy
    $argv[++$x]       // The item to check for is the next item from input
  }++;                // Post increment, the var is now truthy
);
echo $x;              // Echo the index of the duplicate.

Tweaks

  • Saved 12 bytes by using variables instead of an array
  • Saved 6 bytes by making use of the "undefined behavior" rule for when there is no match.
  • Saved 6 bytes by using post-increment instead of setting to 1 after each loop

Complexity

As can be seen from the commented version of the code, the time complexity is linear O(n). In terms of memory, a maximum of n+1 variables will be assigned. So that's O(n).


Thanks for not using a weird encoding. But you should add the error_reporting option to the byte count (or use -n, which is free).
Titus

We've been here before. PHP notices and warnings are ignorable. I might as well pipe them to /dev/null, which is the same.
aross

I tend to remember the wrong comments. :) Isn´t this O(n)?
Titus

Yes it's linear
aross

How is that O(1) for additional space? You're literally assigning a new variable per n, which is O(n)
Xanderhall

2

Java 8, 82 78 76 bytes No longer viable, 75 67 64 bytes below in edit

As a lambda function:

a->{Set<Long>s=new HashSet<>();for(long i:a)if(!s.add(i))return i;return-1;}

Probably can be made much smaller, this was very quick.

Explanation:

a->{                                //New lambda function with 'a' as input
    Set<Long>s=new HashSet<>();     //New set
    for(long i:a)                   //Iterate over a
        if(!s.add(i))               //If can't add to s, already exists
            return i;               //Return current value
        return-1;                   //No dupes, return -1
}

*Edit*

75 67 64 bytes using the negation strategy:

a->{int i=0,j;while((a[j=Math.abs(a[i++])-1]*=-1)<0);return++j;}

Try it online!

(-3 bytes thanks to @Nevay)

Explanation:

a->{                                         //New lambda expression with 'a' as input
    int i=0,j;                               //Initialise i and declare j
    while((a[j=Math.abs(a[i++])-1]*=-1)<0);  //Negate to keep track of current val until a negative is found
    return++j;                               //Return value
}

Loops over the array, negating to keep track. If no dupes, just runs over and throws an error.

Both of these work on O(n) time and O(n) space complexity.


It's worth noting that this will need to be assigned to a lambda returning Number, since i is a long and -1 is an int.
Jakob

@Jakob Not necessary, -1 being an int will automatically be cast to a long without explicitly specifying the cast
SchoolBoy

It will cast implicitly to long, but not to Long as required for the lambda to be assigned to a Function. Did you test it? Regardless, that solution can be replaced with your new one.
Jakob

You can use raw types Set s=new HashSet(); to save 7 bytes. (Besides: afaik the import of java.util.*; has to be included into the byte count -> +19 bytes.) The return statement can be return++j, the if-statement can be removed a->{int i=0,j;for(;(a[j=Math.abs(a[i++])-1]*=-1)<0;);return++j;} (-3 bytes).
Nevay

2

Brachylog, 5 bytes

a⊇=bh

Try it online!

Explanation

a⊇=bh  Input is a list.
a      There is an adfix (prefix or suffix) of the input
 ⊇     and a subsequence of that adfix
  =    whose elements are all equal.
   b   Drop its first element
    h  and output the first element of the rest.

The adfix built-in a lists first all prefixes in increasing order of length, then suffixes in decreasing order of length. Thus the output is produced by the shortest prefix that allows it, if any. If a prefix has no duplicates, the rest of the program fails for it, since every subsequence of equal elements has length 1, and the first element of its tail doesn't exist. If a prefix has a repeated element, we can choose the length-2 subsequence containing both, and the program returns the latter.


Another 5 bytes solution: a⊇Ċ=h, which only looks at length-2 subsets.
Fatalize

1

C#, 145 bytes

using System.Linq;a=>{var d=a.Where(n=>a.Count(t=>t==n)>1);return d.Select((n,i)=>new{n,i}).FirstOrDefault(o=>d.Take(o.i).Contains(o.n))?.n??-1;}

Probably a lot shorter way to do this in C# with a simple loop but I wanted to try it with Linq.

Try it online!

Full/Formatted version:

namespace System.Linq
{
    class P
    {
        static void Main()
        {
            Func<int[], int> f = a =>
            {
                var d = a.Where(n => a.Count(t => t == n) > 1);
                return d.Select((n, i) => new { n, i }).FirstOrDefault(o => d.Take(o.i).Contains(o.n))?.n ?? -1;
            };

            Console.WriteLine(f(new[] { 2, 3, 3, 1, 5, 2 }));
            Console.WriteLine(f(new[] { 2, 4, 3, 5, 1 }));

            Console.ReadLine();
        }
    }
}

Here is the simple loop version. But I like the Linq version much more.
LiefdeWen

@LiefdeWen Post it as an answer :) Though I do usually like Linq better too :) Might be able to get it shorter with Linq too but I'm now sure.
TheLethalCoder

Nah, this question is overpopulated and I would rather you get the up-votes for this question.
LiefdeWen

1

Haskell, 78 69 bytes

 fst.foldl(\(i,a)(j,x)->(last$i:[j|i<0,elem x a],x:a))(-1,[]).zip[1..]

Try it online!

Saved 9 bytes thanks to @nimi

A basic path through the list. If the current element has not yet been seen (i<0) and is in the accumulator list (elem x a) then store the current index. Else, keep the index -1. In any case, add the current element to the accumulator list.

EDIT: I did not read the question carefully enough: this code outputs the index of the second element of a duplicate element.


You can use the "Shorter Conditional" from our "Tips for golfing in Haskell": \ ... ->(last$i:[j|i<0,elem x a],x:a). Also: no need for the f=, because unnamed functions are allowed.
nimi

@nimi thanks for the tip!
jferard

1

Python 2, 71 65 bytes

Returns None if there is no duplicate element

Edit: -6 bytes thanks to @musicman523

def f(n):
 for a in n:
	u=-abs(a)
	if n[u]<0:return-u
	n[u]=-n[u]

Try it online!

O(n) time complexity, O(n) space complexity, O(1) auxiliary space.

As the input list uses O(n) space, the space complexity is bound by this. Meaning we cannot have a lower space complexity than O(n)

Does modify the original list, if this is not allowed we could do it in the same complexity with 129 bytes

Explanation

Since every element is greater than 0 and less than or equal to the size of the list, the list has for each element a, an element on index a - 1 (0 indexed). We exploit this by saying that if the element at index i is negative, we have seen it before.

For each element a in the list n, we let u be negative the absolute value of a. (We let it be negative since python can index lists with negative indices, and we would otherwise need to do u=abs(a)-1) If the element at index u in the list is negative, we have seen it before and can therefore return -u (to get the absolute value of a, as all elements are positive). Else we set the element at index u to be negative, to remember that we have seen an element of value a before.


Nice job! 65 bytes
musicman523

Are you sure this is O(1) in memory? You are still using n bits of memory to store what numbers have already been visited, even though the bits are in the sign. It seems to me that this is O(n) in disguise
Wheat Wizard

Technically this uses O(n) space - the n sign bits. If the array can only hold values between 1 and n, like how it was given, then it obviously doesn't work.
Oliver Ni

This really just comes down to the representation you choose for the numbers. If unsigned numbers are used, then this is O(n) auxiliary space. If signed numbers are used, then the sign bit is already there, meaning O(1) auxiliary space.
Halvard Hummel

I agree with you there. I personally would let you slide using signed integers as long as you didn't use the sign bit, it should be about the algorithm not the technicalities of the system. That being said I do think if you are going to use the sign bits you have to count them. I think this answer is pretty clever. If I any votes left today I would upvote it to counteract the downvote.
Wheat Wizard

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.