Da el número más pequeño que tiene N divisores


17

Su función toma un número natural y devuelve el número natural más pequeño que tiene exactamente esa cantidad de divisores, incluido él mismo.

Ejemplos:

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 función no tiene que devolver la lista de divisores, solo están aquí para los ejemplos.


2
¿Es este código de golf o código de desafío?
marinus

¡Vaya, se olvidó de esa etiqueta, código golf!
SteeveDroz

Respuestas:


6

APL, 25 24 23 caracteres

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

Define una función fque luego puede usarse para calcular los números:

> f 13
4096

> f 14
192

La solución utiliza el hecho de que LCM (n, x) == n iff x divide n . Por lo tanto, el bloque {+/⍵=⍵∧⍳⍵}simplemente calcula el número de divisores. Esta función se aplica a todos los números del 1 al 2 ^ d ¨⍳2*⍵ . Luego se busca en la lista resultante d sí mismo ( ⍳⍵), que es la función deseada f (d) .


Felicidades! 23 personajes ... ¡guau!
SteeveDroz

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

No creo que necesites definirlo f.
Zacharý

5

GolfScript, 29 28 caracteres

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

Editar: se puede guardar un único carácter si restringimos la búsqueda a <2 ^ n, gracias a Peter Taylor por esta idea.

Versión previa:

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

Un intento en GolfScript, ejecutar en línea .

Ejemplos:

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

El código contiene esencialmente tres bloques que se explican en detalle en las siguientes líneas.

# 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)

Parece entrar en un bucle infinito para la entrada 1.
Peter Taylor

Hasta ahora, mi mejor solución toma mucho de la tuya, en la medida en que creo que merece ser un comentario en lugar de una respuesta por separado.
Peter Taylor

4

Python: 64

Al revisar la solución de Bakuriu e incorporar la sugerencia de grc, así como el truco de la solución R de plannapus, obtenemos:

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)

Lo anterior elevará un RuntimeError: maximum recursion depth exceededcon pequeñas entradas en CPython, e incluso establecer el límite en un gran número probablemente dará algunos problemas. En las implementaciones de Python que optimizan la recursividad de la cola, debería funcionar bien.

Una versión más detallada, que no debería tener tales limitaciones, es la siguiente solución de 79 bytes:

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

Estoy llegando al límite de recursividad en 11, 13, 17, 19 y otros.
Steven Rumbalski el

@StevenRumbalski Nadie mencionó que el programa debería funcionar con enteros arbitrarios. Desafortunadamente, los números crecen bastante rápido incluso con pequeñas entradas.
Bakuriu

Puede guardar algunos caracteres mediante el reemplazo if elsecon and ory ==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

Debido a que encuentro 66 un poco demasiado malvado, puedes guardar 2 caracteres si lo usassum(k%-~i<1for i in range(k))
Volatility

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

4

Mathematica 38 36

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

Uso:

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

Resultado:

498960

Editar

Alguna explicación:

DivisorSum [n, form] representa la suma de la forma [i] para todo i que divide n.

Como form[i]estoy usando la función 1 &, eso siempre regresa 1, calculando tan efectivamente la suma de los divisores de una manera concisa.


No había una etiqueta de código de golf, ¡así que di una respuesta larga! oops
DavidC

@DavidCarraher que acabo de adivinar :)
Dr. belisarius

Pensé que sabía qué DivisorSumretorna (la suma de los divisores) pero no veo cómo eso es instrumental para responder la pregunta planteada. ¿Podría explicar cómo funciona? Por cierto, creo que debería incluir datos de tiempo para n = 200; la función es notablemente rápida, dados todos los números que tuvo que verificar.
DavidC

@DavidCarraher Ver edición. Re: tiempos - Mi máquina es demasiado lenta :(
Dr. belisarius

¿Mathematica no tiene suficientes elementos integrados para que el enfoque más sofisticado en torno a la factorización sea más corto? Si ese es el caso, estoy decepcionado.
Peter Taylor

3

J, 33 caracteres

Bastante rápido, pasa por todos los números más pequeños y calcula el número de divisores en función de la factorización.

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

   f 19
262144

3

Haskell 54

Solución rápida y sucia (tan legible y no complicada):

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

La edición no hizo que la respuesta fuera más corta, pero tal vez sea más como un haskell. También siempre he incluido la nueva línea final a la longitud de mi código, ¿está mal?
shiona

Pensé que has contado mal; El objetivo principal de la edición era actualizar el recuento. El cambio en el código en sí mismo fue menor. Creo que las otras entradas aquí tampoco cuentan la nueva línea final, como por ejemplo la entrada para J (33 caracteres).
Will Ness

2

K, 42

Solución recursiva ineficiente que explota la pila con bastante facilidad.

{{$[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 

Ejemplo:

F 6
12           

2

APL (25)

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

Tramposo! echo -n '{⍵ {⍺ = + / 0 = ⍵ | ⍨⍳⍵: ⍵⋄⍺∇⍵ + 1} 1}' | wc -c me da 47! Pero realmente, ¿podría darme un enlace a algún tutorial fácil para APL? Traté de buscarlo en Google y he leído algunos artículos, pero al final siempre quiero preguntar "¿Por qué están haciendo esto :(?". Nunca he trabajado con ningún lenguaje de sintaxis no ASCII y quiero saber si tiene alguna ventaja real.
XzKto

Esto es para Dyalog APL, que es lo que yo uso, puede descargar la versión de Windows de forma gratuita en el mismo sitio. dyalog.com/MasteringDyalogAPL/MasteringDyalogAPL.pdf
marinus

Wow, parece que realmente puedo entender esto. ¡Gracias por el enlace! El único inconveniente es que tienen una política de licencias muy extraña, pero tal vez solo necesito mejorar mi inglés)
XzKto

2

R - 47 caracteres

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

!n%%1:nda un vector de booleanos: VERDADERO cuando un entero de 1 a n es un divisor de n y FALSO si no. sum(!n%%1:n)coacciona booleanos a 0 si es FALSO y 1 si es VERDADERO y los suma, de modo que N-sum(...)es 0 cuando el número de divisores es N. 0 se interpreta entonces como FALSO porwhile cual se detiene.

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}

Realmente solo hay 46 personajes significativos:

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

Probablemente debería aprender un idioma con una sintaxis más corta :)


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 caracteres

Podría verse como una mejora de la solución anterior de Haskell, pero fue concebida por derecho propio (advertencia: es muy lenta):

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

Es una función bastante interesante, por ejemplo, tenga en cuenta que f (p) = 2 ^ (p-1), donde p es un número primo.


La manera eficiente, en lugar de corta, de calcularlo sería factorizar nen números primos (con repetición), ordenar descendentes, disminuir cada uno, comprimir con una secuencia infinita de números primos y luego doblar el producto dep^(factor-1)
Peter Taylor

2
@PeterTaylor No es necesario. Para n = 16 = 2 * 2 * 2 * 2 la solución es 2 ^ 3 * 3 ^ 1 * 5 ^ 1 = 120, no 2 ^ 1 * 3 ^ 1 * 5 ^ 1 * 7 ^ 1 = 210.
randomra

2

C: 66 64 caracteres

Una solución casi corta:

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

Y mi solución anterior que no se repite:

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

Deben existir soluciones mucho más cortas.


2

Haskell (120C), un método muy eficiente

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)]

Código de prueba:

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

Este método es muy rápido. La idea es primero encontrar los factores primos de k=p1*p2*...*pm, donde p1 <= p2 <= ... <= pm. Entonces la respuesta es n = 2^(pm-1) * 3^(p(m-1)-1) * 5^(p(m-2)-1) ....

Por ejemplo, factorizando k = 18, obtenemos 18 = 2 * 3 * 3. Los primeros 3 primos son 2, 3, 5. Entonces la respuesta n = 2 ^ (3-1) * 3 ^ (3-1) * 5 ^ (2-1) = 4 * 9 * 5 = 180

Puedes probarlo en 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

¡Es un puntaje de golf pobre, pero +1 por el camino que has tomado!
SteeveDroz

Para 8 = 2 * 2 * 2 este algoritmo da el número 2 * 3 * 5 = 30. Pero la mejor solución es 2 ^ 3 * 3 = 24 (para 8 = 2 * 4)
AMK

La solución es incorrecta si el número especificado de divisores contiene una alta potencia de primo pequeño. Por lo tanto, las soluciones enumeradas más probablemente para potencias de 10 son incorrectas.
AMK

@AMK Sí, tienes razón. Gracias por señalar eso.
Ray

2

Brachylog , 2 bytes

fl

Pruébalo en línea!

Toma entradas a través de su variable de salida y salidas a través de su variable de entrada.

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

Este mismo predicado exacto, tomando la entrada a través de su variable de entrada y emitiendo a través de su variable de salida, resuelve este desafío en su lugar .


Agradable, pero no elegible para ese rompecabezas ya que el lenguaje es más reciente que la pregunta.
SteeveDroz

Cuando era nuevo aquí, una de las primeras cosas que me dijeron fue que los idiomas más nuevos que las preguntas ya no son incompetentes, y esto está respaldado por meta: codegolf.meta.stackexchange.com/questions/12877/…
String no relacionado

Oh bueno, no importa entonces. Aparentemente, las reglas están hechas para evolucionar y debemos tener en cuenta que el propósito principal de este sitio es mejorarnos y divertirnos. Respuesta aceptada!
SteeveDroz

1

C, 69 caracteres

No es el más corto, pero la primera respuesta 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)cuenta divisores de nen el rango 1..s. Así f(n,n)cuenta los divisores de n.
g(d)bucles (por recursión) hasta f(x,x)==d, luego devuelve x.


1

Mathematica 38 36

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

Uso

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

(* 64 *)

Primera entrada (antes de code-golfagregar la etiqueta a la pregunta).

Un problema sencillo, dado que Divisors[n]devuelve los divisores de n(incluido n) y Length[Divisors[n]]devuelve el número de dichos divisores. **

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

Ejemplos

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

Gráficos de Mathematica


David, más bajo y más rápido de lo que Length@Divisors@nes DivisorSigma[0,n].
Mr.Wizard

Gracias. No sabía sobre ese uso de DivisorSigma.
DavidC


1

Gelatina , 6 bytes (no competitiva)

2*RÆdi

Pruébalo en línea! o verificar todos los casos de prueba .

Cómo funciona

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.

¿Por qué haces 2*? ¿Es que cada número después de eso tiene más divisores que n?
Erik the Outgolfer

2
No; por ejemplo, todos los números primos tienen exactamente dos divisores. Sin embargo, estamos buscando el menor entero positivo con n divisores. Como 2**(n-1)pertenece a ese rango, el más pequeño también.
Dennis

0

C ++, 87 caracteres

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 caracteres, no recursivo

Un poco más detallado que las otras soluciones de Python, pero no es recursivo, por lo que no alcanza el límite de recurrencia de 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 caracteres

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

Ejemplo de uso:

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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.