Дайте наименьшее число, которое имеет N делителей


17

Ваша функция принимает натуральное число и возвращает наименьшее натуральное число, которое имеет именно такое количество делителей, включая себя.

Примеры:

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

Функция не должна возвращать список делителей, они только здесь для примеров.


2
Это код-гольф или код-вызов?
Marinus

Ой, забыл об этом теге, код-гольф!
SteeveDroz

Ответы:


6

APL, 25 24 23 символа

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

Определяет функцию, fкоторую затем можно использовать для вычисления чисел:

> f 13
4096

> f 14
192

Решение использует тот факт, что LCM (n, x) == n, если x делит n . Таким образом, блок {+/⍵=⍵∧⍳⍵}просто вычисляет количество делителей. Эта функция применяется ко всем числам от 1 до 2 ^ d ¨⍳2*⍵ . Полученный список затем искали г самого ( ⍳⍵) , которая является искомой функцией F (d) .


Congrats! 23 персонажа ... вау!
SteeveDroz

19:{⍵⍳⍨(+/⊢=⊢∧⍳)¨⍳2*⍵}
Адам

Я не думаю, что вам нужно определить f.
Захари

5

GolfScript, 29 28 символов

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

Редактировать: один символ может быть сохранен, если мы ограничим поиск до <2 ^ n, спасибо Питеру Тейлору за эту идею.

Предыдущая версия:

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

Попытка в GolfScript, запустить онлайн .

Примеры:

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

Код содержит в основном три блока, которые подробно описаны в следующих строках.

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

Кажется, чтобы войти в бесконечный цикл для ввода 1.
Питер Тейлор

Мое лучшее решение до сих пор довольно сильно заимствует у вас, насколько я думаю, что оно заслуживает того, чтобы быть комментарием, а не отдельным ответом.
Питер Тейлор

4

Python: 64

Пересматривая решение Бакуриу и включив в него предложение grc, а также хитрость решения R планнапа, мы получаем:

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)

Вышеприведенное приведёт к RuntimeError: maximum recursion depth exceededнебольшому количеству входных данных в CPython, и даже если установить ограничение на огромное количество, это, вероятно, вызовет некоторые проблемы. На реализациях Python, которые оптимизируют хвостовую рекурсию, она должна работать нормально.

Более подробной версией, которая не должна иметь таких ограничений, является следующее 79- байтовое решение:

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

Я достигаю предела рекурсии 11, 13, 17, 19 и других.
Стивен Румбальски

@ StevenRumbalski Никто не упомянул, что программа должна работать с произвольными целыми числами. К сожалению, цифры растут довольно быстро даже при небольших затратах.
Бакуриу

Вы можете сохранить некоторые символы с помощью замены if elseна and orи ==1с <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

Поскольку я считаю 66 слишком злым, вы можете сохранить 2 символа, если используетеsum(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)экономит 7 байт.
Деннис

4

Mathematica 38 36

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

Использование:

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

Результат:

498960

редактировать

Некоторое объяснение:

DivisorSum [n, form] представляет сумму формы [i] для всех i, которые делят n.

Поскольку form[i]я использую функцию 1 &, она всегда возвращает результат 1, поэтому эффективно вычисляет сумму делителей кратким образом.


Не было тега code-golf, поэтому я дал длинный ответ! упс
DavidC

@DavidCarraher Я только что догадался :)
Доктор Белизарий

Я думал, что знаю, что DivisorSumвозвращает (сумма делителей), но я не понимаю, как это полезно для ответа на поставленный вопрос. Не могли бы вы объяснить, как это работает. Кстати, я думаю, что вы должны включить данные синхронизации для n = 200; функция удивительно быстрая, учитывая все числа, которые она должна была проверить.
DavidC

@DavidCarraher См редактировать. Re: время - Моя машина слишком медленно :(
Доктор Белизарий

Разве Mathematica не имеет достаточно встроенных компонентов для более сложного подхода к факторингу, чтобы быть короче? Если это так, я разочарован.
Питер Тейлор

3

J, 33 знака

Довольно быстро, проходит через все меньшие числа и вычисляет количество делителей на основе факторизации.

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

   f 19
262144

3

Haskell 54

Быстрое и грязное (настолько удобочитаемое и не хитрое) решение:

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

Редактирование не сделало ответ короче, но, возможно, он более похож на хаскель. Кроме того, я всегда включал завершающий перевод строки в длину моего кода, это неправильно?
Шион

Я думал, что вы ошиблись; Основной целью редактирования было обновление счета. Изменение в самом коде было незначительным. Я думаю, что другие записи здесь также не учитывают завершающий символ новой строки, как, например, запись для J (33 символа).
Уилл Несс

2

К, 42

Неэффективное рекурсивное решение, которое легко взрывает стек

{{$[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 (25)

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

Жулик! echo -n '{⍵ {⍺ = + / 0 = ⍵ | ⍨⍳⍵: ⍵⋄⍺∇⍵ + 1} 1}' | wc -c дает мне 47! Но действительно, не могли бы вы дать мне ссылку на простое руководство по APL? Я попытался найти его в Google и прочитал несколько статей, но все же в конце я всегда хочу спросить: «Почему они это делают :(?». Я никогда не работал с любым синтаксическим языком, отличным от ASCII, и хочу выяснить, у него есть какое-то реальное преимущество
XzKto

Это для Dyalog APL, который я использую, вы можете бесплатно скачать версию для Windows на том же сайте. dyalog.com/MasteringDyalogAPL/MasteringDyalogAPL.pdf
marinus

Вау, похоже, я действительно могу понять это. Спасибо за ссылку! Единственным недостатком является то, что у них очень странная политика лицензирования, но, может быть, мне просто нужно улучшить свой английский)
XzKto

2

R - 47 символов

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

!n%%1:nдает вектор логических значений: TRUE, когда целое число от 1 до n является делителем n, и FALSE, если нет. sum(!n%%1:n)Приводит логические значения к 0, если FALSE, и 1, если TRUE, и суммирует их, так что N-sum(...)0, когда число делителей равно N. 0, затем интерпретируется как FALSE какwhile после чего останавливается.

Использование:

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}

На самом деле есть только 46 значащих символов:

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

Я, вероятно, должен выучить язык с более коротким синтаксисом :)


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

2

Хаскель: 49 символов

Это можно рассматривать как улучшение более раннего решения на Haskell, но оно было задумано само по себе (предупреждение: оно очень медленное):

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

Это довольно интересная функция, например, обратите внимание, что f (p) = 2 ^ (p-1), где p - простое число.


Эффективный, в отличие от короткого, способ его вычисления состоит в том, чтобы разложить nна простые числа (с повторениями), отсортировать по убыванию, уменьшить на единицу, сжать с бесконечной последовательностью простых чисел, а затем сложить произведениеp^(factor-1)
Питер Тейлор,

2
@PeterTaylor Не обязательно. Для n = 16 = 2 * 2 * 2 * 2 решение равно 2 ^ 3 * 3 ^ 1 * 5 ^ 1 = 120, а не 2 ^ 1 * 3 ^ 1 * 5 ^ 1 * 7 ^ 1 = 210.
randomra

2

C: 66 64 символа

Почти краткое решение:

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

И мое предыдущее решение, которое не повторяется:

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

Должны существовать гораздо более короткие решения.


2

Haskell (120C), очень эффективный метод

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

Тестовый код:

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

Этот метод очень быстрый. Идея состоит в том, чтобы сначала найти основные факторы k=p1*p2*...*pm, где p1 <= p2 <= ... <= pm. Тогда ответ n = 2^(pm-1) * 3^(p(m-1)-1) * 5^(p(m-2)-1) ....

Например, разложив k = 18, мы получим 18 = 2 * 3 * 3. Первые 3 простых числа равны 2, 3, 5. Таким образом, ответ n = 2 ^ (3-1) * 3 ^ (3-1) * 5 ^ (2-1) = 4 * 9 * 5 = 180

Вы можете проверить это в 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

Это плохой результат в гольфе, но +1 за пройденный путь!
SteeveDroz

Для 8 = 2 * 2 * 2 этот алгоритм дает число 2 * 3 * 5 = 30. Но лучшее решение - 2 ^ 3 * 3 = 24 (для 8 = 2 * 4)
AMK

Решение является неправильным, если указанное число делителей содержит большую степень малого простого числа. Так что, скорее всего, перечисленные решения для степеней 10 неверны.
AMK

@AMK Да, ты прав. Спасибо что подметил это.
Рэй

2

Brachylog , 2 байта

fl

Попробуйте онлайн!

Принимает ввод через свою выходную переменную и выводит через свою входную переменную.

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

Точно такой же предикат, принимающий ввод через свою входную переменную и выводящий через выходную переменную, вместо этого решает эту проблему .


Хорошо, но не подходит для этой загадки, поскольку язык более свежий, чем вопрос.
SteeveDroz

Когда я был здесь новичком,
Unrelated String

Ну что ж, тогда неважно. Видимо, правила созданы для того, чтобы развиваться, и мы должны помнить, что главная цель этого сайта - улучшить себя и повеселиться. Ответ принят!
SteeveDroz

1

C 69 символов

Не самый короткий, но первый ответ 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)рассчитывает делителей nв диапазоне 1..s. Так f(n,n)считает делителей n.
g(d)циклы (рекурсией) доf(x,x)==d , затем возвращает х.


1

Mathematica 38 36

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

использование

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

(* 64 *)

Первая запись (до code-golfдобавления тега к вопросу.)

Простая проблема, учитывая, что Divisors[n]возвращает делители n(в том числе n) и Length[Divisors[n]]возвращает количество таких делителей. **

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

Примеры

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

Математическая графика


Дэвид, короче и быстрее чем Length@Divisors@nесть DivisorSigma[0,n].
Mr.Wizard

Благодарю. Я не знал об этом использовании DivisorSigma.
DavidC


1

Желе , 6 байт (не конкурирует)

2*RÆdi

Попробуйте онлайн! или проверьте все контрольные примеры .

Как это устроено

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.

Почему ты это делаешь 2*? Неужели каждый номер после этого имеет больше делителей, чем n?
Эрик Outgolfer

2
Нет; например, все простые числа имеют ровно два делителя. Однако мы ищем наименьшее натуральное число с n делителями. Так как 2**(n-1)принадлежит к этому диапазону, наименьший тоже.
Деннис


0

Python2, 95 символов, нерекурсивный

Немного более многословно, чем в других решениях Python, но оно нерекурсивно, поэтому оно не достигает предела рекурсии 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)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.