Дайте найменше число, яке має 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 iff x ділить n . Таким чином, блок {+/⍵=⍵∧⍳⍵}просто обчислює кількість дільників. Ця функція застосовується до всіх чисел від 1 до 2 ^ d ¨⍳2*⍵ . Потім в результаті отриманого списку шукається d d ( ⍳⍵), що є бажаною функцією f (d) .


Вітаю! 23 символи ... ух!
SteeveDroz

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

Я не думаю, що вам потрібно визначатись f.
Zacharý

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

Пітон: 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

Пітон: 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))
Волатильність

f=lambda n,k=1:n==sum(k%-~i<1for i in range(k))or-~f(n,k+1)економить 7 байт.
Денніс

4

Математика 38 36

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

Використання:

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

Результат:

498960

Редагувати

Деякі пояснення:

DivisorSum [n, форма] являє собою суму форми [i] для всіх i, що ділять n.

Оскільки form[i]я використовую функцію 1 &, яка повертається завжди 1, настільки ефективно обчислюючи суму дільників короткочасним способом.


Тегу код-гольф не було, тому я дав довгу відповідь! oops
DavidC

@DavidCarraher Я просто здогадався :)
Dr. belisarius

Я думав, що знаю, що 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]

Редагування не зробило відповіді коротшою, але, можливо, вона більше схожа на haskell. Також я завжди включав у свій код тривалість нового рядка, це неправильно?
shiona

Я думав, що ти зробив неправильний рахунок; Основна мета редагування - оновити кількість. Сама зміна коду була незначною. Я думаю, що інші записи тут також не враховують проміжок нового рядка, як, наприклад, запис для 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, то інтерпретується як FALSEwhile якому потім зупиняється.

Використання:

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

Haskell: 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

С: 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

Брахілог , 2 байти

fl

Спробуйте в Інтернеті!

Приймає вхід через свою вихідну змінну і виводить через свою вхідну змінну.

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

Цей точно такий же предикат, приймаючи вхід через свою вхідну змінну і виводячи через свою вихідну змінну, вирішує замість цього завдання .


Приємно, але не підходить до цієї загадки, оскільки мова є останнім часом, ніж питання.
SteeveDroz

Коли я був тут новим, одне з перших, що мені сказали - це те, що мови, новіші за запитання, вже не конкурують, і це підкріплюється мета: codegolf.meta.stackexchange.com/questions/12877/…
рядок

Ну добре, тоді не майте на увазі. Мабуть, правила розробляються, і ми повинні пам’ятати, що головна мета цього сайту - вдосконалити себе та розважитися. Відповідь прийнято!
SteeveDroz

1

C, 69 символів

Не найкоротша, але перша відповідь:

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

Математика 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

Mathematica graphics


Девід, коротший і швидший, ніж 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?
Ерік Аутгольфер

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.