Список перших n простих чисел найбільш ефективно та в найкоротшому коді [закрито]


27

Правила прості:

  • Перші n праймів (не праймес нижче n ) повинні бути надруковані до стандартного виводу, розділеного новими рядками (прайми повинні бути згенеровані в коді)
  • праймери не можуть бути згенеровані вбудованою функцією або через бібліотеку , тобто використання вбудованої або бібліотечної функції, наприклад, prime = get_nth_prime (n), is_a_prime (число), або факторист = list_all_factors (число), не буде дуже творчим.
  • Оцінка балів - Скажімо, ми визначаємо Score = f ([число знаків у коді]), O ( f (n)) є складністю вашого алгоритму, де n - кількість простих значень, які він знаходить. Так, наприклад, якщо у вас є 300 char код із складністю O (n ^ 2), оцінка становить 300 ^ 2 = 90000 , для 300 символів з O (n * ln (n)) оцінка стає 300 * 5,7 = 1711,13 ( припустимо, щоб усі журнали були натуральними для простоти)

  • Використовуйте будь-яку існуючу мову програмування, виграйте найнижчий бал

Редагувати: Проблема була змінена з пошуку "перших 1000000 простих" на "перших n простих" через плутанину щодо того, що "n" в O (f (n)) є, n - кількість простих праймів, які ви знайдете (знаходження праймес - проблема тут і тому складність проблеми залежить від кількості знайдених простих чисел)

Примітка: щоб уточнити деякі плутанини щодо складності, якщо 'n' - це кількість знайдених простих чисел, а 'N' - n-й найдений найрізноманітніший, складність з точки зору n є і N не еквівалентні, тобто O (f (n))! = O (f (N)) як, f (N)! = Константа * f (n) і N! = Константа * n, тому що ми знаємо, що n-та проста функція не є лінійною, хоча, оскільки ми знаходили 'n' Складність праймесів повинна бути легко вираженою через «n».

Як вказував Kibbee, ви можете відвідати цей сайт, щоб перевірити свої рішення ( ось старий список документів Google)

Будь ласка, включіть їх у своє рішення -

  • яку складність має ваша програма (включайте базовий аналіз, якщо не тривіальний)

  • довжина символу коду

  • підсумковий розрахунковий бал

Це моє перше запитання CodeGolf, тому, якщо є помилка чи лазівка ​​у вищезазначених правилах, будь ласка, вкажіть їх.



2
Моєю відповіддю за це була 1[\p:i.78498моя відповідь на це буде 1[\p:i.1000000. Навіть якщо припустити, що внутрішній простий алгоритм J - це O (n ^ 2), моя оцінка все одно складе лише 196.
Гарет

2
Здається, ніхто не вдається правильно розрахувати їх складність. Існує плутанина щодо того, чи nє кількість простих чи максимальних простих, і всі ігнорують той факт, що додавання чисел у діапазоні 0..nє O(logn), а множення та ділення ще дорожче. Я пропоную вам навести кілька прикладних алгоритмів разом з їх правильною складністю.
угорен

3
Поточний найвідоміший тест первинності для k-бітового числа є O-tilde(k^6). Це призводить до того, що кожен, хто претендує на час роботи краще, ніж O-tilde(n ln n (ln(n ln n))^6)неправильно зрозумів частину проблеми; і до питання про те, як O-tildeслід розбирати складності в оцінці.
Пітер Тейлор

2
Ніхто не вказував, що O (n) еквівалентний O (kn) (для постійної k) за складністю, але не в бальних показниках. Наприклад, припустимо, що моя складність становить O (n ^ 10). Це еквівалентно O (n ^ 10 * 1E-308), і я все ще можу виграти виклик з величезною програмою з жахливою складністю.
JDL

Відповіді:


10

Python (129 символів, O (n * журнал журналу n), оцінка 203,948)

Я б сказав, що Сита Ератосфена - це шлях. Дуже просто і відносно швидко.

N=15485864
a=[1]*N
x=xrange
for i in x(2,3936):
 if a[i]:
  for j in x(i*i,N,i):a[j]=0
print [i for i in x(len(a))if a[i]==1][2:]

Поліпшений код від раніше.

Python ( 191 156 152 символів, O (n * log log n) (?), Оцінка 252.620 (?))

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

from math import log as l
n=input()
N=n*int(l(n)+l(l(n)))
a=range(2,N)
for i in range(int(n**.5)+1):
 a=filter(lambda x:x%a[i] or x==a[i],a)
print a[:n]

n*int(l(n)+l(l(n)))є верхньою межею числа nпершого числа.


1
Розрахунок складності (і, таким чином, оцінка) ґрунтується на верхній межі, nале не на кількості простих чисел. Таким чином, я припускаю, що оцінка повинна бути вищою. Дивіться мій коментар вище.
Говард

Верхня зв'язана n? Що це?
beary605

Верхня межа тут N=15485864. Для розрахунків складності на основі n=1000000, ви можете сказати N=n*log(n)(через щільність простих ліній).
ugoren

Якщо мій рахунок потрібно зафіксувати, будь ласка, виправте його, я все ще не дуже добре розумію систему балів.
beary605

@ beary605 було б нормально, якби я змінив проблеми на пошук перших n простих? це вирішило б багато плутанини щодо складності та того, що n є в O (f (n))
Optimus

7

Haskell, n ^ 1,1 емпіричний темп зростання, 89 символів, оцінка 139 (?)

Наступні роботи в GHCi підказують, коли загальна бібліотека, яку він використовує, була раніше завантажена. Роздрукувати n -й прайм, на основі 1:

let s=3:minus[5,7..](unionAll[[p*p,p*p+2*p..]|p<-s])in getLine>>=(print.((0:2:s)!!).read)

Це необмежене сито Ератостена з використанням бібліотеки загального користування для упорядкованих списків. Емпірична складність між 100 000 і 200 000 праймерами O(n^1.1). Підходить до O(n*log(n)*log(log n)).

Про оцінку складності

Я виміряв час виконання для 100k і 200k праймес, потім обчислив logBase 2 (t2/t1), який дав n^1.09. Визначення g n = n*log n*log(log n), розрахунок logBase 2 (g 200000 / g 100000)дає n^1.12.

Тоді 89**1.1 = 139, хоча g(89) = 600. --- (?)

Здається, що для оцінки оцінюваного темпу зростання слід використовувати замість самої функції складності. Наприклад, g2 n = n*((log n)**2)*log(log n)набагато краще n**1.5, але за 100 знаків обидві результати отримують бал 3239і 1000, відповідно. Це не може бути правильним. Оцінка на 200k / 100k діапазоні дає logBase 2 (g2 200000 / g2 100000) = 1.2і, таким чином, бал 100**1.2 = 251.

Крім того, я не намагаюся надрукувати всі праймери, а лише n -й прайм.

Без імпорту, 240 символів. n ^ 1,15 емпіричний темп зростання, оцінка 546.

main=getLine>>=(print.s.read)
s n=let s=3:g 5(a[[p*p,p*p+2*p..]|p<-s])in(0:2:s)!!n
a((x:s):t)=x:u s(a$p t)
p((x:s):r:t)=(x:u s r):p t
g k s@(x:t)|k<x=k:g(k+2)s|True=g(k+2)t
u a@(x:r)b@(y:t)=case(compare x y)of LT->x:u r b;EQ->x:u r t;GT->y:u a t

5

Haskell, 72 89 символів, O (n ^ 2), оцінка 7921

Найвищий бал за кількість перемог, чи не так? Модифікований для першого N. Також я, мабуть, не можу використовувати калькулятор, тому моя оцінка не настільки погана, як я думав. (використовуючи складність для базового пробного поділу, як показано у джерелі нижче).

Відповідно до Вілла Несса, наведене нижче не є повноцінною програмою Haskell (вона фактично покладається на REPL). Далі йде більш повна програма з псевдоситом (імпорт насправді заощаджує знак, але мені не подобається імпорт у коді гольфу).

main=getLine>>= \x->print.take(read x).(let s(x:y)=x:s(filter((>0).(`mod`x))y)in s)$[2..]

Ця версія, безсумнівно, (n ^ 2). Алгоритм - це просто версія для гольфу наївного `` сита '', як видно тут Old Ghci 1 лайнер

getLine>>= \x->print.take(read x)$Data.List.nubBy(\x y->x`mod`y==0)[2..]

Залишати стару, обманюючу відповідь, тому що бібліотека, до якої вона посилається, дуже приємна.

print$take(10^6)Data.Numbers.Primes.primes

Дивіться тут про реалізацію та посилання на часові складності. На жаль колеса мають час пошуку журналу (n), уповільнюючи нас фактором.


• праймери не можуть бути згенеровані вбудованим функтоном або через бібліотеку
beary605

@walpen Вибачте, що я змінив правила без повідомлення, будь ласка, внесіть зміни, як вважаєте за потрібне
Optimus

Невже складність не така, як O ((n ln n) ^ 1,5 ln (n ln n) ^ 0,585)? (Або O ((n ln n) ^ 1,5 ln (n ln n)), якщо Haskell використовує наївний поділ, а не, як я припустив, Карацуба)
Пітер Тейлор

Ні, тому що це дає мені жахливу оцінку: /. Але я впевнений, що ти маєш рацію. Це просто виглядало як пробний поділ, і це часова складність судового поділу (можливо, за моїм поганим розумінням читання можливого неправильного джерела), тому я вибрав це. Поки що я буду називати свою оцінку NaN, що здається безпечним.
проходити

Я припускаю (мій Haskell мізерно малий, але я знаю, як було б природно це зробити в SML ...), що ви проводите пробний поділ лише меншими прайсами, і в цьому випадку пробний поділ на P робить O ( P ^ 0,5 / ln P) поділи. Але якщо P має k біт, ділення приймає час O (k ^ 1.585) (Карацуба) або O (k ^ 2) (наивно), і вам потрібно пропустити через O (n lg n) числа довжини O (ln ( n lg n)) біт.
Пітер Тейлор

5

C #, 447 символів, байтів 452, оцінка?

using System;namespace PrimeNumbers{class C{static void GN(ulong n){ulong primes=0;for (ulong i=0;i<(n*3);i++){if(IP(i)==true){primes++;if(primes==n){Console.WriteLine(i);}}}}static bool IP(ulong n){if(n<=3){return n>1;}else if (n%2==0||n%3==0){return false;}for(ulong i=5;i*i<=n;i+=6){if(n%i==0||n%(i+2)==0){return false;}}return true;}static void Main(string[] args){ulong n=Convert.ToUInt64(Console.ReadLine());for(ulong i=0;i<n;i++){GN(i);}}}}

Варіант сценаріїв, 381 персонажів, 385 байт, оцінка?

using System;static void GetN(ulong n){ulong primes=0;for (ulong i=0;i<(n*500);i++){if(IsPrime(i)==true){primes++;if(primes==n){Console.WriteLine(i);}}}}public static bool IsPrime(ulong n){if(n<=3){return n>1;}else if (n%2==0||n%3==0){return false;}for(ulong i=5;i*i<=n;i+=6){if(n%i==0||n%(i+2)==0){return false;}}return true;}ulong n=Convert.ToUInt64(Console.ReadLine());for(ulong i=0;i<n;i++){GetN(i);}

Якщо ви встановите scriptcs, ви можете запустити його.

PS Я написав це у Vim :D


2
Ви можете зберегти деякі символи, видаливши зайву пробіл. Наприклад, не потрібно ставити пробіл навколо =та <підписувати. Крім того, я не думаю, що для цього коду є різниця в байтах і символах - це 548 символів і 548 байт.
ProgramFOX

2
О, дякую, це мій перший CodeGolf!
XiKuuKy

4

GolfScript (45 знаків, заявлений рахунок ~ 7708)

~[]2{..3${1$\%!}?={.@\+\}{;}if)1$,3$<}do;\;n*

Це робить простий пробний поділ на прими. Якщо поблизу переднього краю Ruby (тобто з використанням 1.9.3.0) арифметика використовує множення Toom-Cook 3, тож пробний поділ становить O (n ^ 1.465), а загальна вартість підрозділів - O((n ln n)^1.5 ln (n ln n)^0.465) = O(n^1.5 (ln n)^1.965)†. Однак у GolfScript додавання елемента до масиву вимагає копіювання масиву. Я оптимізував це, щоб скопіювати список простих ліній лише тоді, коли він знайде нове просте число, тож лише nраз. Кожна операція копіювання - це O(n)елементи розміром O(ln(n ln n)) = O(ln n)†, надаючи O(n^2 ln n).

І це, хлопці та дівчата, саме тому GolfScript використовується для гольфу, а не для серйозних програм.

O(ln (n ln n)) = O(ln n + ln ln n) = O(ln n) . Я мав це помітити, перш ніж коментувати різні пости ...


4

Це так просто, що навіть мій текстовий редактор може це зробити!

Vim: 143 натискання клавіш (115 дій): O (n ^ 2 * log (n)): Оцінка: 101485.21

Подання:

qpqqdqA^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"ddmpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0qqpmp"aywgg@dqgg@p

Введення: N має бути в першому рядку порожнього документа. Після цього кожне просте від 2 до N буде окремим рядком.

Запуск команд:

По-перше, зауважте, що будь-які команди з каретою перед ними означають, що вам потрібно утримувати Ctrl і вводити наступну букву (наприклад, ^ V є Ctrl-vі ^ R єCtrl-r ).

Це перезаписать будь-що у ваших регістрах @a, @b, @d та @p.

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

  • qpqqdq просто очищає регістри
  • A^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"ddстворить список чисел від 2 до N + 1. Це перерва між двома основними частинами, тож коли це буде зроблено, вам не потрібно буде робити це знову
  • mpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0qqpmp"aywgg@dqgg@pце потрібно ввести за один раз. Намагайтеся уникати зворотної області, оскільки це може щось викрутити.
    • Якщо ви помилилися, введіть, qdqqpqа потім спробуйте цей рядок ще раз.

Для великих N це дуже повільно. Пробіг N = 5000 пройшов близько 27 хвилин; вважайте себе попередженим.

Алгоритм:

Для цього використовується базовий рекурсивний алгоритм пошуку прайметів. Враховуючи список усіх простих чисел між 1 і A, A + 1 є простим, якщо він не ділиться на жодне з чисел у списку простих чисел. Почніть з A = 2 і додайте праймери до списку, коли вони знайдені. Після N рекурсій, список буде містити всі праймери до N.

Складність

Цей алгоритм має складність O (nN), де N - вхідне число, а n - кількість простих чисел до N. Кожна рекурсійна перевірка n чисел, а N рекурсій виконується, даючи O (nN).

Однак N ~ n * log (n), надаючи остаточну складність як O (n 2 * log (n)) ( https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number )

Пояснення

Виявити потік програми з команд vim непросто, тому я переписав її в Python, слідуючи тим же потоком. Як і код Vim, і пітон буде помилятися, коли він досягне кінця. Python не любить занадто багато рекурсії; якщо ви спробуєте цей код з N> 150 або більше, він досягне максимальної глибини рекурсії

N = 20
primes = range(2, N+1)

# Python needs these defined.
mark_p = b = a = -1

# Check new number for factors. 
# This macro could be wrapped up in @d, but it saves space to leave it separate.
def p():
    global mark_d, mark_p, primes, a
    mark_d = 0
    print(primes)
    a = primes[mark_p]
    d()      

# Checks factor and determine what to do next
def d():
    global mark_d, mark_p, a, b, primes
    b = primes[mark_d]
    if(a == b): # Number is prime, check the next number
        mark_p += 1
        p()
    else:
        if(a%b == 0): # Number is not prime, delete it and check next number
            del(primes[mark_p])
            p()
        else: # Number might be prime, try next possible factor
            mark_d += 1
            d()

mark_p = 0 #Start at first number         
p()

Тепер, щоб розбити фактичні натискання клавіш!

  • qpqqdqОчищає регістри @d і @p. Це забезпечить нічого не запускається при налаштуванні цих рекурсивних макросів.

  • A^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"ddПеретворює вхід у список чисел від 2 до N + 1. Запис N + 1 видаляється як побічний ефект налаштування макросу @d.

    • Зокрема, пише макрос, який збільшує число, потім копіює його в наступному рядку, потім пише 1 і виконує цей макрос N разів.
  • mpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0qпише макрос @d, який реалізує функцію d () вище. Висловлювання "якщо" цікаво реалізувати у Vim. За допомогою пошукового оператора * можна вибрати певний шлях, який слід пройти. Розбиваючи команду далі, ми отримуємо

    • mpqdТут встановіть позначку p і починайте записувати макрос @d. Позначення p потрібно встановити, щоб було відоме місце, до якого слід переходити
    • o^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc> Записує текст твердження if / else
    • 0*w*wyiWdd@0 фактично виконує оператор if.
    • Перед виконанням цієї команди рядок буде містити @a @b 0 0 `pj@p @a 0 (@a%@b) `pdd@p 0 `dj@d
    • 0 переміщує курсор на початок рядка
    • *w*w Переміщує курсор до коду для виконання наступного

      1. якщо @a == @b, тобто `pj@pпереходить до наступного числа для @a і працює на ньому @p.
      2. якщо @a! = @b і @ a% @ b == 0, тобто `pdd@pвидаляє поточне число @a, після чого запускає @p на наступне.
      3. якщо @a! = @b і @ a %% b! = 0, тобто `dj@dякий перевіряє наступне число на @b, щоб побачити, чи є він фактором @a
    • yiWdd@0 передає команду в регістр 0, видаляє рядок і запускає команду

    • q завершує запис макросу @d
  • Коли це перший запуск, `pdd@pкоманда виконується, видаляючи рядок N + 1.

  • qpmp"aywgg@dq пише макрос @p, який зберігає число під курсором, потім переходить до першого запису і виконує @d на цьому.

  • gg@p насправді виконує @p, щоб він повторював весь файл.


3

QBASIC, 98 знаків, складність N Sqrt (N), оцінка 970

I=1
A:I=I+2
FOR J=2 TO I^.5
    IF I MOD J=0 THEN GOTO A
NEXT
?I
K=K+1
IF K=1e6 THEN GOTO B
GOTO A
B:

Я трохи змінив заяву про проблему, її тепер знайдіть перші "n 'primes, пробачте, що не отримали сповіщення
Optimus

Я припускаю, що ми можемо припустити "вхідний" вхід для цієї програми; тобто вхід - це цифра відразу після IF K=(тому довжина програми не буде включати цифру). Наразі програма виводить перші п простих ліній, не включаючи 2, які можна виправити додаванням ?2на початку та зміною K=...на K=...-1. Програма також може бути golfed трохи, беручи простору зі стану J=2 TO, J=0 THEN, K=...-1 THENта шляхи видалення відступів. Я вважаю, що це призводить до 96-символьної програми.
res

3

Скала 263 символи

Оновлено, щоб відповідати новим вимогам. 25% коду стосується пошуку розумної верхньої межі для обчислення простих ліній нижче.

object P extends App{
def c(M:Int)={
val p=collection.mutable.BitSet(M+1)
p(2)=true
(3 to M+1 by 2).map(p(_)=true)
for(i<-p){
var j=2*i;
while(j<M){
if(p(j))p(j)=false
j+=i}
}
p
}
val i=args(0).toInt
println(c(((math.log(i)*i*1.3)toInt)).take(i).mkString("\n"))
}

У мене теж було сито.

Ось емпіричний тест калькуляції витрат, не прийнятий для аналізу:

object PrimesTo extends App{
    var cnt=0
    def c(M:Int)={
        val p=(false::false::true::List.range(3,M+1).map(_%2!=0)).toArray
        for (i <- List.range (3, M, 2)
            if (p (i))) {
                var j=2*i;
                while (j < M) {
                    cnt+=1
                    if (p (j)) 
                        p(j)=false
                    j+=i}
            }
        (1 to M).filter (x => p (x))
    }
    val i = args(0).toInt
    /*
        To get the number x with i primes below, it is nearly ln(x)*x. For small numbers 
        we need a correction factor 1.13, and to avoid a bigger factor for very small 
        numbers we add 666 as an upper bound.
    */
    val x = (math.log(i)*i*1.13).toInt+666
    println (c(x).take (i).mkString("\n"))
    System.err.println (x + "\tcount: " + cnt)
}
for n in {1..5} ; do i=$((10**$n)); scala -J-Xmx768M P $i ; done 

призводить до таких підрахунків:

List (960, 1766, 15127, 217099, 2988966)

Я не впевнений, як підрахувати бал. Чи варто написати ще 5 символів?

scala> List(4, 25, 168, 1229, 9592, 78498, 664579, 5761455, 50847534).map(x=>(math.log(x)*x*1.13).toInt+666) 
res42: List[Int] = List(672, 756, 1638, 10545, 100045, 1000419, 10068909, 101346800, 1019549994)

scala> List(4, 25, 168, 1229, 9592, 78498, 664579, 5761455, 50847534).map(x=>(math.log(x)*x*1.3)toInt) 
res43: List[Int] = List(7, 104, 1119, 11365, 114329, 1150158, 11582935, 116592898, 1172932855)

Для більшої n це зменшує обчислення приблизно на 16% у цьому діапазоні, але afaik для формули оцінки ми не вважаємо постійними факторами?

нові міркування Big-O:

Щоб знайти 1 000, 10 000, 100 000 праймерів і так далі, я використовую формулу про щільність простих чисел x => (math.log (x) * x * 1.3, яка визначає зовнішній цикл, який я виконую.

Отже, для значень i в 1 до 6 => NPrimes (10 ^ i) працює 9399, 133768 ... разів більше зовнішньої петлі.

Я знайшов цю О-функцію ітеративно за допомогою коментаря Пітера Тейлора, який запропонував набагато вищі значення для експоненції, замість 1,01 він запропонував 1,5:

def O(n:Int) = (math.pow((n * math.log (n)), 1.01)).toLong

O: (n: Int) Довгий

val ns = List(10, 100, 1000, 10000, 100000, 1000*1000).map(x=>(math.log(x)*x*1.3)toInt).map(O) 

ns: Список [Довгий] = Список (102, 4152, 91532, 1612894, 25192460, 364664351)

 That's the list of upper values, to find primes below (since my algorithm has to know this value before it has to estimate it), send through the O-function, to find similar quotients for moving from 100 to 1000 to 10000 primes and so on: 

(ns.head /: ns.tail)((a, b) => {println (b*1.0/a); b})
40.705882352941174
22.045279383429673
17.62109426211598
15.619414543051187
14.47513863274964
13.73425213148954

Це коефіцієнти, якщо я використовую 1,01 як показник. Ось те, що лічильник виявляється емпірично:

ns: Array[Int] = Array(1628, 2929, 23583, 321898, 4291625, 54289190, 660847317)

(ns.head /: ns.tail)((a, b) => {println (b*1.0/a); b})
1.799140049140049
8.051553431205189
13.649578085909342
13.332251210010625
12.65003116535112
12.172723833234572

Перші два значення - це інші, тому що я маю постійну корекцію для моєї оцінки формули для малих значень (до 1000).

З пропозицією Пітера Тейлора 1,5 виглядатиме так:

245.2396265560166
98.8566987153728
70.8831374743478
59.26104390040363
52.92941829568069
48.956394784317816

Тепер зі своєю цінністю я добираюся:

O(263)
res85: Long = 1576

Але я не впевнений, наскільки я можу підійти зі своєю О-функцією до спостережуваних значень.


Вибачте, що я внесла деякі зміни в постановку проблеми, щоб зменшити деяку неоднозначність, пов’язану зі складністю, (я впевнений, що ваше рішення не зміниться сильно)
Optimus

Це фактично пробний поділ на праймери. Кількість разів через внутрішню петлю O(M^1.5 / ln M), і кожен раз, коли ви робите O(ln M)роботу (додавання), так що в цілому це O(M^1.5) = O((n ln n)^1.5).
Пітер Тейлор

З ^ 1,02 замість ^ 1,5 def O(n:Int) = (math.pow((n * math.log (n)), 1.02)).toLongя наближаюся до значень, емпірично знайдених за допомогою мого лічильника. Я вкладаю свої висновки у свій пост.
користувач невідомий

3

Рубін 66 знаків, О (п ^ 2) Оцінка - 4356

lazyдоступний з Ruby 2.0, і 1.0/0це крутий трюк, щоб отримати нескінченний діапазон:

(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j==0}}.take(n).to_a

1
Ви можете поголити один шар, змінивши його на(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j<1}}.take(n).to_a
Qqwy

Або навіть: (Це робить рішення менш ефективним, але воно не змінює верхню межу O (n²)) (2..(1.0/0)).lazy.select{|i|(2..i).one?{|j|i%j<1}}.take(n).to_a. Це збриває ще двох персонажів.
Qqwy

Добре змінивши його, (2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j<1}}.first(n)це призведе до 61 символу.
Річі

2

Рубі, 84 символів, 84 байти, оцінка?

Цей, мабуть, трохи занадто новачок для цих частин, але мені було весело це робити. Він просто циклічний, поки f(знайдені primes) не дорівнює nпотрібної кількості простих ліній, які потрібно знайти.

Забавна частина полягає в тому, що для кожного циклу він створює масив від 2 до одного менше числа, що перевіряється. Потім він відображає кожен елемент у масиві як модуль вихідного числа та елемента, і перевіряє, чи будь-який з результатів дорівнює нулю.

Також я не маю уявлення, як це забити.

Оновлення

Код ущільнений і включає (абсолютно довільне) значення для n

n,f,i=5**5,0,2
until f==n;f+=1;p i if !(2...i).to_a.map{|j|i%j}.include?(0);i+=1;end

Оригінал

f, i = 0, 2
until f == n
  (f += 1; p i) if !(2...i).to_a.map{|j| i % j}.include?(0)
  i += 1
end

i += 1Біт і untilпетлі є свого роду стрибки на мене , як області для поліпшення, але на цій трасі я начебто застряг. У всякому разі, було цікаво думати.


2

Скала, 124 символи

object Q extends App{Stream.from(2).filter(p=>(2 to p)takeWhile(i=>i*i<=p)forall{p%_!= 0})take(args(0)toInt)foreach println}

Простий пробний поділ до квадратного кореня. Отже, складність повинна бути O (n ^ (1,5 + epsilon))

124 ^ 1,5 <1381, так що, як я вважаю, я вважаю?


1

Perl - 94 символи, O (n log (n)) - Оцінка: 427

perl -wle '$n=1;$t=1;while($n<$ARGV[0]){$t++;if((1x$t)!~/^1?$|^(11+?)\1+$/){print $t;$n++;}}'

Пітон - 113 символів

import re
z = int(input())
n=1
t=1
while n<z:
    t+=1
    if not re.match(r'^1?$|^(11+?)\1+$',"1"*t):
        print t
        n+=1

1

AWK, 96 86 байт

Підзаголовок: Подивися мамо! Лише додавання та деяка бухгалтерія!

Файл fsoe3.awk:

{for(n=2;l<$1;){if(n in L)p=L[n]
else{print p=n;l++}
for(N=p+n++;N in L;)N+=p
L[N]=p}}

Виконати:

$ awk -f fsoe3.awk <<< 5
2
3
5
7
11
$ awk -f fsoe3.awk <<< 1000 | wc -l
1000

БАШ, 133 байт

Файл x.bash:

a=2
while((l<$1));do if((b[a]))
then((c=b[a]));else((c=a,l++));echo $a;fi;((d=a+c))
while((b[d]));do((d+=c));done
((b[d]=c,a++));done

Виконати:

$ bash x.bash 5
2
3
5
7
11
$ bash x.bash 1000 | wc -l
1000

Примери обчислюються, пускаючи вже знайдені прайми стрибати на "стрічці натуральних чисел". В основному це серіалізоване сито Ератостена.

from time import time as t

L = {}
n = 2
l = 0

t0=t()

while l<1000000:

        if n in L:
                P = L[n]
        else:
                P = n
                l += 1
                print t()-t0

        m = n+P
        while m in L:
                m += P
        L[m] = P

        n += 1

... той самий алгоритм в Python і друкує час, коли l-й прайм був знайдений замість самого прайму.

Вихід, нанесений на графік, gnuplotдає наступне:

введіть тут опис зображення

Стрибки, ймовірно, мають щось спільне із затримкою вводу-виводу файлів через запис буферизованих даних на диск ...

Використання набагато більшої кількості прайсів для пошуку принесе додаткові затримки, залежні від системи, в грі, наприклад, масив, що представляє "стрічку додатних цілих чисел", постійно зростає, і рано чи пізно кожен комп'ютер буде плакати за більшою кількістю оперативної пам'яті (або пізнішим підміненням).

... тож уявлення про складність, переглядаючи експериментальні дані, насправді не дуже допомагає ... :-(


Тепер підраховуємо доповнення, необхідні для пошуку nпростих ліній:

cells = {}
current = 2
found = 0

additons = 0

while found < 10000000:

        if current in cells:
                candidate = cells[current]
                del cells[current] # the seen part is irrelevant
        else:
                candidate = current
                found += 1 ; additons += 1
                print additons

        destination = current + candidate ; additons += 1
        while destination in cells:
                destination += candidate ; additons += 1
        cells[destination] = candidate

        current += 1 ; additons += 1

введіть тут опис зображення


Як ти склав ці графіки?
кіт

1
Gnuplotз, set term xtermа потім скріншот xtermграфічного вікна 's (можливо, майже забута функція). ;-)

0

Scala 121 (99 без котла основного класу)

object Q extends App{Stream.from(2).filter{a=>Range(2,a).filter(a%_==0).isEmpty}.take(readLine().toInt).foreach(println)}

0

Python 3, 117 106 байт

Це рішення є дещо тривіальним, оскільки воно виводить 0, де число не є простим, але я все-таки опублікую його:

r=range
for i in[2]+[i*(not 0 in[i%j for j in r(3,int(i**0.5)+1,2)])for i in r(3,int(input()),2)]:print(i)

Крім того, я не впевнений, як розробити складність алгоритму. Будь ласка, не зволікайте через це. Натомість будьте приємні та прокоментуйте, як я міг це розробити. Також розкажіть, як я міг би це скоротити.


Я думаю , що ви можете поставити print(i)на тій же лінії, що і для циклу і видалити пробіли в in [2], 0 if, 0 in [i%jта +1,2)] else.
акроліт

@daHugLenny Вау, спасибі велике! Я відредагую свою публікацію через секунду. :-D
0WJYxW9FMN

@daHugLenny Чи знаєте ви, як обчислити ефективність випадково?
0WJYxW9FMN

Ні вибач. (Коментарі мають бути не менше 15 символів)
акроліт

Все одно, дякую. Ви зробили тут мою програму найкоротшою!
0WJYxW9FMN


0

Perl 6, 152 байти, O (n log n log (n log n) log (log (n log n))) (?), 9594,79 балів

Відповідно до цієї сторінки , бітова складність пошуку всіх простих чисел до n становить O (n log n log log n); вищевказана складність використовує той факт, що n-й простий пропорційний n log n.

my \N=+slurp;my \P=N*(N.log+N.log.log);my @a=1 xx P;for 2..P.sqrt ->$i {if @a[$i] {@a[$_*$i]=0 for $i..P/$i}};say $_[1] for (@a Z ^P).grep(*[0])[2..N+1]

не кваліфікується, зробіть це в Wentel, щоб пройти кваліфікацію
noɥʇʎԀʎzɐɹƆ

Пробачте, але що ви маєте на увазі?
bb94

для щедроти (fiiiiiiiiilerrrrr)
noɥʇʎԀʎzɐɹƆ

0

Groovy (50 байт) - O (n * sqrt (n)) - оцінка 353.553390593

{[1,2]+(1..it).findAll{x->(2..x**0.5).every{x%it}}​}​

Приймає в n і виводить усі числа від 1 до n, які є простими.

Алгоритм, який я вибрав, лише виводить праймери n> 2, тому додавання 1,2 на початку потрібно.

Зламатися

x%it - Неявна правда, якщо вона не ділиться, хибна, якщо вона є.

(2..x**0.5).every{...}- Для всіх значень між 2 та sqrt (x) переконайтесь, що вони не поділяються, щоб це повернуло істину, повинно повернути true для кожного .

(1..it).findAll{x->...} - Для всіх значень від 1 до n знайдіть усі, що відповідають критеріям нерозділення між 2 та sqrt (n).

{[1,2]+...}​ - Додайте 1 і 2, оскільки вони завжди прості і ніколи не охоплені алгоритмом.


0

Ракетка 155 байт

(let p((o'(2))(c 3))(cond[(>=(length o)n)(reverse o)][(ormap(λ(x)(= 0(modulo c x)))
(filter(λ(x)(<= x(sqrt c)))o))(p o(add1 c))][(p(cons c o)(add1 c))]))

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

Безголівки:

(define(nprimes n)
  (let loop ((outl '(2))                   ; outlist having primes being created
             (current 3))                  ; current number being tested
  (cond
    [(>= (length outl) n) (reverse outl)]  ; if n primes found, print outlist.
    [(ormap (λ(x) (= 0 (modulo current x))) ; test if divisible by any previously found prime
            (filter                         ; filter outlist till sqrt of current number
             (λ(x) (<= x (sqrt current)))
             outl))
     (loop outl (add1 current)) ]           ; goto next number without adding to prime list
    [else (loop (cons current outl) (add1 current))] ; add to prime list and go to next number
    )))

Тестування:

(nprimes 35)

Вихід:

'(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149)

0

awk 45 (складність N ^ 2)

інший awk, для праймерів до 100 використання, як це

awk '{for(i=2;i<=sqrt(NR);i++) if(!(NR%i)) next} NR>1' <(seq 100)

код гольф рахується частина

{for(i=2;i<=sqrt(NR);i++)if(!(NR%i))next}NR>1

який можна помістити у файл сценарію та запустити як awk -f prime.awk <(seq 100)


0

Javascript, 61 символ

f=(n,p=2,i=2)=>p%i?f(n,p,++i):i==p&&n--&alert(p)||n&&f(n,++p)

Трохи гірше, ніж O (n ^ 2), для великих n буде не вистачати місця у стеці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.