Dai il numero più piccolo che ha N divisori


17

La tua funzione prende un numero naturale e restituisce il numero naturale più piccolo che ha esattamente quella quantità di divisori, incluso se stesso.

Esempi:

f(1) =  1 [1]
f(2) =  2 [1, 2]
f(3) =  4 [1, 2, 4]
f(4) =  6 [1, 2, 3, 6]
f(5) = 16 [1, 2, 4, 8, 16]
f(6) = 12 [1, 2, 3, 4, 6, 12]
 ...

La funzione non deve restituire l'elenco dei divisori, sono solo qui per gli esempi.


2
Questo code-golf o code-challenge?
Marin

Oops, ho dimenticato quell'etichetta, code-golf!
SteeveDroz,

Risposte:


6

APL, 25 24 23 caratteri

f←{({+/⍵=⍵∧⍳⍵}¨⍳2*⍵)⍳⍵}

Definisce una funzione fche può quindi essere utilizzata per calcolare i numeri:

> f 13
4096

> f 14
192

La soluzione utilizza il fatto che LCM (n, x) == n iff x divide n . Pertanto, il blocco {+/⍵=⍵∧⍳⍵}calcola semplicemente il numero di divisori. Questa funzione è applicata a tutti i numeri da 1 a 2 ^ d ¨⍳2*⍵ . L'elenco risultante viene quindi cercato d stesso ( ⍳⍵) che è la funzione desiderata f (d) .


Congratulazioni! 23 personaggi ... wow!
SteeveDroz,

19:{⍵⍳⍨(+/⊢=⊢∧⍳)¨⍳2*⍵}
Adám,

Non penso che tu debba definire f.
Zacharý,

5

GolfScript, 29 28 caratteri

{.{\.,{)1$\%},,-=}+2@?,?}:f;

Modifica: un singolo carattere può essere salvato se limitiamo la ricerca a <2 ^ n, grazie a Peter Taylor per questa idea.

Versione precedente:

{.{\)..,{)1$\%},,-@=!}+do}:f;

Un tentativo in GolfScript, eseguito online .

Esempi:

13 f p  # => 4096
14 f p  # => 192
15 f p  # => 144

Il codice contiene essenzialmente tre blocchi che sono spiegati in dettaglio nelle seguenti righe.

# Calculate numbers of divisors
#         .,{)1$\%},,-    
# Input stack: n
# After application: D(n)

.,          # push array [0 .. n-1] to stack
{           # filter array by function
  )         #   take array element and increase by one
  1$\%      #   test division of n ($1) by this value
},          # -> List of numbers x where n is NOT divisible by x+1
,           # count these numbers. Stack now is n xd(n)
-           # subtracting from n yields the result



# Test if number of divisors D(n) is equal to d
#         {\D=}+   , for D see above
# Input stack: n d
# After application: D(n)==d

{
  \         # swap stack -> d n
  D         # calculate D(n) -> d D(n)
  =         # compare
}+          # consumes d from stack and prepends it to code block         



# Search for the first number which D(n) is equal to d
#         .T2@?,?    , for T see above
# Input stack: d
# After application: f(d)

.           # duplicate -> d d
T           # push code block (!) for T(n,d) -> d T(n,d)
2@?         # swap and calculate 2^d -> T(n,d) 2^d
,           # make array -> T(n,d) [0 .. 2^d-1]
?           # search first element in array where T(n,d) is true -> f(d)

Sembra andare in un ciclo infinito per l'input 1.
Peter Taylor,

La mia migliore soluzione finora prende in prestito abbastanza pesantemente dalla tua, nella misura in cui penso che meriti di essere un commento piuttosto che una risposta separata.
Peter Taylor,

4

Python: 64

Revisionando la soluzione di Bakuriu e incorporando il suggerimento di grc e il trucco della soluzione R di plannapus, otteniamo:

f=lambda n,k=1:n-sum(k%i<1for i in range(1,k+1))and f(n,k+1)or k

4

Python: 66

f=lambda n,k=1:n==sum(k%i<1for i in range(1,k+1))and k or f(n,k+1)

Quanto sopra aumenterà a RuntimeError: maximum recursion depth exceededcon piccoli input in CPython, e anche impostando il limite su un numero enorme, probabilmente ci saranno dei problemi. Sulle implementazioni Python che ottimizzano la ricorsione della coda, dovrebbe funzionare bene.

Una versione più dettagliata, che non dovrebbe avere tali limitazioni, è la seguente soluzione di 79 byte:

def f(n,k=1):
    while 1:
        if sum(k%i<1for i in range(1,k+1))==n:return k
        k+=1

Sto raggiungendo il limite di ricorsione su 11, 13, 17, 19 e altri.
Steven Rumbalski,

@StevenRumbalski Nessuno ha menzionato il fatto che il programma dovrebbe funzionare con numeri interi arbitrari. Sfortunatamente i numeri crescono abbastanza velocemente anche con piccoli input.
Bakuriu,

Puoi salvare alcuni caratteri usando la sostituzione if elsecon and ore ==1con <1:f=lambda n,k=1:n==sum(k%i<1for i in range(1,k+1))and k or f(n,k+1)
grc

Poiché trovo 66 un po 'troppo malvagio, puoi usare 2 personaggi se usisum(k%-~i<1for i in range(k))
Volatilità il

f=lambda n,k=1:n==sum(k%-~i<1for i in range(k))or-~f(n,k+1)salva 7 byte.
Dennis,

4

Mathematica 38 36

(For[i=1,DivisorSum[++i,1&]!=#,];i)&

Uso:

(For[i=1,DivisorSum[++i,1&]!=#,];i)&@200

Risultato:

498960

modificare

Qualche spiegazione:

DivisorSum [n, form] rappresenta la somma della forma [i] per tutti i che dividono n.

Mentre form[i]sto usando la funzione 1 &, questo ritorna sempre 1, calcolando in modo efficace la somma dei divisori in modo conciso.


Non c'era un tag code-golf quindi ho dato una risposta lunga! oops
DavidC

@DavidCarraher Ho appena indovinato :)
Dr. belisarius,

Pensavo di sapere cosa DivisorSumritorna (la somma dei divisori) ma non vedo come ciò sia fondamentale per rispondere alla domanda posta. Spiegheresti come funziona. A proposito, penso che dovresti includere i dati di temporizzazione per n = 200; la funzione è notevolmente veloce, dati tutti i numeri che ha dovuto controllare.
DavidC,

@DavidCarraher Vedi modifica. Ri: tempistiche - La mia macchina è troppo lenta :(
Dr. belisarius

Mathematica non ha abbastanza elementi integrati per ridurre l'approccio più sofisticato al factoring? In tal caso, sono deluso.
Peter Taylor,

3

J, 33 caratteri

Abbastanza veloce, passa attraverso tutti i numeri più piccoli e calcola il numero di divisori in base alla fattorizzazione.

   f=.>:@]^:([~:[:*/[:>:_&q:@])^:_&1

   f 19
262144

3

Haskell 54

Soluzione rapida e sporca (così leggibile e non complicata):

f k=head[x|x<-[k..],length[y|y<-[1..x],mod x y==0]==k]

La modifica non ha reso la risposta più breve, ma è forse più simile a un haskell. Inoltre ho sempre incluso la nuova riga finale del mio codice, è sbagliato?
shiona,

Pensavo avessi contato male; lo scopo principale per la modifica era aggiornare il conteggio. La modifica del codice stesso è stata minima. Penso che anche le altre voci qui non contino la nuova riga finale, come ad esempio la voce per J (33 caratteri).
Will Ness,

2

K, 42

Soluzione ricorsiva inefficiente che fa esplodere la pila abbastanza facilmente

{{$[x=+/a=_a:y%!1+y;y;.z.s[x;1+y]]}[x;0]} 

.

k){{$[x=+/a=_a:y%!1+y;y;.z.s[x;1+y]]}[x;0]}14
192
k){{$[x=+/a=_a:y%!1+y;y;.z.s[x;1+y]]}[x;0]}13
'stack

2

APL 33

F n            
i←0              
l:i←i+1          
→(n≠+/0=(⍳i)|i)/l
i 

Esempio:

F 6
12           

2

APL (25)

{⍵{⍺=+/0=⍵|⍨⍳⍵:⍵⋄⍺∇⍵+1}1}

Cheater! echo -n '{⍵ {⍺ = + / 0 = ⍵ | ⍨⍳⍵: ⍵⋄⍺∇⍵ + 1} 1}' | wc -c mi dà 47! Ma davvero, potresti darmi un link ad un semplice tutorial per APL? Ho provato a cercarlo su Google e ho letto alcuni articoli, ma alla fine voglio sempre chiedere "Perché lo stanno facendo :(?". Non ho mai lavorato con nessun linguaggio di sintassi non ASCII e voglio scoprire se ha qualche vantaggio reale.
XzKto

Questo è per Dyalog APL, che è quello che uso, puoi scaricare gratuitamente la versione di Windows dallo stesso sito. dyalog.com/MasteringDyalogAPL/MasteringDyalogAPL.pdf
marinus

Wow, sembra che riesca davvero a capirlo. Grazie per il link! L'unico aspetto negativo è che hanno una politica delle licenze molto strana, ma forse ho solo bisogno di migliorare il mio inglese)
XzKto

2

R - 47 caratteri

f=function(N){n=1;while(N-sum(!n%%1:n))n=n+1;n}

!n%%1:nfornisce un vettore di booleani: VERO quando un numero intero compreso tra 1 e n è un divisore di n e FALSE in caso contrario. sum(!n%%1:n)costringe i booleani a 0 se FALSO e 1 se VERO e li somma, quindi questo N-sum(...)è 0 quando il numero di divisori è N. 0 viene quindi interpretato come FALSO con il whilequale poi si ferma.

Uso:

f(6)
[1] 12
f(13)
[1] 4096

2

Javascript 70

function f(N){for(j=i=m=1;m-N||j-i;j>i?i+=m=j=1:m+=!(i%++j));return i}

In realtà ci sono solo 46 personaggi significativi:

for(j=i=m=1;m-N||j-i;j>i?i+=m=j=1:m+=!(i%++j))

Probabilmente dovrei imparare una lingua con sintassi più breve :)


N=>eval("for(j=i=m=1;m-N||j-i;j>i?i+=m=j=1:m+=!(i%++j));i")
TuxCrafting

2

Haskell: 49 personaggi

Potrebbe essere visto come un miglioramento della precedente soluzione Haskell, ma è stato concepito a sé stante (attenzione: è molto lento):

f n=until(\i->n==sum[1|j<-[1..i],rem i j<1])(+1)1

È una funzione abbastanza interessante, ad esempio nota che f (p) = 2 ^ (p-1), dove p è un numero primo.


Il modo efficiente, piuttosto che breve, di calcolarlo sarebbe quello di fattorizzare nin numeri primi (con ripetizione), ordinare in ordine decrescente, decrescere ciascuno, comprimere con una sequenza infinita di numeri primi e quindi piegare il prodotto dip^(factor-1)
Peter Taylor,

2
@PeterTaylor Non necessario. Per n = 16 = 2 * 2 * 2 * 2 la soluzione è 2 ^ 3 * 3 ^ 1 * 5 ^ 1 = 120, non 2 ^ 1 * 3 ^ 1 * 5 ^ 1 * 7 ^ 1 = 210.
randomra,

2

C: 66 64 caratteri

Una soluzione quasi breve:

i;f(n){while(n-g(++i));return i;}g(j){return j?!(i%j)+g(j-1):0;}

E la mia precedente soluzione che non ricorre:

i;j;k;f(n){while(k-n&&++i)for(k=0,j=1;j<=i;k+=!(i%j++));return i;}

Devono esistere soluzioni molto più brevi.


2

Haskell (120C), un metodo molto efficiente

1<>p=[]
x<>p|mod x p>0=x<>(p+1)|1<2=(div x p<>p)++[p]
f k=product[p^(c-1)|(p,c)<-zip[r|r<-[2..k],2>length(r<>2)](k<>2)]

Codice di prova:

main=do putStrLn$show$ f (100000::Integer)

Questo metodo è molto veloce. L'idea è prima di trovare i fattori primi di k=p1*p2*...*pm, dove p1 <= p2 <= ... <= pm. Quindi la risposta èn = 2^(pm-1) * 3^(p(m-1)-1) * 5^(p(m-2)-1) ... .

Ad esempio, fattorizzando k = 18, otteniamo 18 = 2 * 3 * 3. I primi 3 numeri primi sono 2, 3, 5. Quindi la risposta n = 2 ^ (3-1) * 3 ^ (3-1) * 5 ^ (2-1) = 4 * 9 * 5 = 180

Puoi testarlo sotto ghci:

*Main> f 18
180
*Main> f 10000000
1740652905587144828469399739530000
*Main> f 1000000000
1302303070391975081724526582139502123033432810000
*Main> f 100000000000
25958180173643524088357042948368704203923121762667635047013610000
*Main> f 10000000000000
6558313786906640112489895663139340360110815128467528032775795115280724604138270000
*Main> f 1000000000000000
7348810968806203597063900192838925279090695601493714327649576583670128003853133061160889908724790000
*Main> f 100000000000000000
71188706857499485011467278407770542735616855123676504522039680180114830719677927305683781590828722891087523475746870000
*Main> f 10000000000000000000
2798178979166951451842528148175504903754628434958803670791683781551387366333345375422961774196997331643554372758635346791935929536819490000
*Main> f 10000000000000000000000
6628041919424064609742258499702994184911680129293140595567200404379028498804621325505764043845346230598649786731543414049417584746693323667614171464476224652223383190000

È un punteggio di golf scadente, ma +1 per il percorso che hai intrapreso!
SteeveDroz,

Per 8 = 2 * 2 * 2 questo algoritmo fornisce il numero 2 * 3 * 5 = 30. Ma la soluzione migliore è 2 ^ 3 * 3 = 24 (per 8 = 2 * 4)
AMK

La soluzione non è corretta se il numero specificato di divisori contiene un alto potere di piccoli numeri primi. Quindi molto probabilmente le soluzioni elencate per poteri di 10 sono sbagliate.
AMK,

@AMK Sì, hai ragione. Grazie per la segnalazione.
Ray,

2

Brachylog , 2 byte

fl

Provalo online!

Riceve input attraverso la sua variabile di output e output attraverso la sua variabile di input.

f     The list of factors of
      the input variable
 l    has length equal to
      the output variable.

Questo stesso predicato esatto, prendendo l'input attraverso la sua variabile di input e emettendo attraverso la sua variabile di output, risolve invece questa sfida .


Bello, ma non idoneo per quel puzzle in quanto la lingua è più recente della domanda.
SteeveDroz,

Quando ero nuovo qui, una delle prime cose che mi è stato detto è che le lingue più nuove delle domande non sono più non competitive, e questo è supportato da meta: codegolf.meta.stackexchange.com/questions/12877/…
Unrelated String

Oh bene, allora non importa. Apparentemente, le regole sono fatte per evolversi e dobbiamo tenere presente che lo scopo principale di questo sito è migliorare noi stessi e divertirci. Risposta accettata!
SteeveDroz,

1

C, 69 caratteri

Non la più breve, ma la prima risposta C:

f(n,s){return--s?f(n,s)+!(n%s):1;}
x;
g(d){return++x,f(x,x)-d&&g(d),x;}

f(n,s)conta divisori nnell'intervallo 1..s. Quindi f(n,n)conta i divisori di n.
g(d)loop (per ricorsione) fino a f(x,x)==d, quindi restituisce x.


1

Mathematica 38 36

(For[k=1,DivisorSigma[0, k]!= #,k++]; k)&

uso

   (For[k = 1, DivisorSigma[0, k] != #, k++]; k) &[7]

(* 64 *)

Primo ingresso (prima delcode-golf tag fosse aggiunto alla domanda.)

Un problema semplice, dato che Divisors[n]restituisce i divisori di n(incluso n) e Length[Divisors[n]]restituisce il numero di tali divisori. **

smallestNumber[nDivisors_] :=
   Module[{k = 1},
   While[Length[Divisors[k]] != nDivisors, k++];k]

Esempi

Table[{i, nDivisors[i]}, {i, 1, 20}] // Grid

Mathematica graphics


David, più basso e più veloce di quello che Length@Divisors@nè DivisorSigma[0,n].
Mr.Wizard,

Grazie. Non sapevo di quell'uso di DivisorSigma.
DavidC


1

Gelatina , 6 byte (non competitiva)

2*RÆdi

Provalo online! o verifica tutti i casi di test .

Come funziona

2*RÆdi  Main link. Argument: n (integer)

2*      Compute 2**n.
  R     Range; yield [1, ..., 2**n]. Note that 2**(n-1) has n divisors, so this
        range contains the number we are searching for.
   Æd   Divisor count; compute the number of divisors of each integer in the range.
     i  Index; return the first (1-based) index of n.

Perché lo fai 2*? Ogni numero successivo ha più divisori di n?
Erik the Outgolfer,

2
No; ad esempio, tutti i numeri primi hanno esattamente due divisori. Tuttavia, stiamo cercando il numero intero positivo più piccolo con n divisori. Poiché 2**(n-1)appartiene a quell'intervallo, anche il più piccolo lo fa.
Dennis,

0

C ++, 87 caratteri

int a(int d){int k=0,r,i;for(;r!=d;k++)for(i=2,r=1;i<=k;i++)if(!(k%i))r++;return k-1;}

0

Python2, 95 caratteri, non ricorsivo

Un po 'più prolisso rispetto alle altre soluzioni Python ma non è ricorsivo, quindi non raggiunge il limite di ricorsione di cpython:

from itertools import*
f=lambda n:next(i for i in count()if sum(1>i%(j+1)for j in range(i))==n)

0

Perl 6 , 39 caratteri

{my \a=$=0;a++while $_-[+] a X%%1..a;a}

Esempio di utilizzo:

say (0..10).map: {my \a=$=0;a++while $_-[+] a X%%1..a;a}
(0 1 2 4 6 16 12 64 24 36 48)
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.