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


27

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

  • Первые n простых чисел (не простых ниже n ) должны быть напечатаны в стандартный вывод, разделенные символами новой строки (простые числа должны быть сгенерированы в коде)
  • простые числа не могут быть сгенерированы встроенной функцией или библиотекой , то есть использование встроенной или библиотечной функции, такой как, prime = get_nth_prime (n), is_a_prime (number) или factorlist = list_all_factors (number), не будет очень креативным.
  • Оценка - скажем, мы определяем Score = f ([число символов в коде]), O ( f (n)) - сложность вашего алгоритма, где n - число простых чисел, которые он находит. Так, например, если у вас есть 300-символьный код со сложностью O (n ^ 2), оценка составляет 300 ^ 2 = 90000 , для 300 знаков с O (n * ln (n)) оценка становится 300 * 5.7 = 1711.13 ( давайте для простоты предположим, что все журналы являются натуральными)

  • Используйте любой существующий язык программирования, выигрывает самый низкий балл

Изменить: проблема была изменена с поиска «первых 1000000 простых чисел» на «первые n простых чисел» из-за путаницы в том, что такое «n» в O (f (n)), n - это число найденных простых чисел (поиск простых чисел проблема здесь и так сложность задачи зависит от числа найденных простых чисел)

Примечание: уточнить некоторые неурядицы на сложности, если «п» число простых чисел , вы найдете и «N» является п - й премьер - Found, сложность в терминах п и N не эквивалентны т.е. O (F (N))! = O (f (N)) as, f (N)! = Постоянная * f (n) и N! = Постоянная * n, потому что мы знаем, что n-я простая функция не является линейной, хотя, так как мы находили 'n' сложность простых чисел должна быть легко выражаемой через 'n'.

Как указал Кибби, вы можете посетить этот сайт, чтобы проверить свои решения ( здесь приведен старый список документов Google)

Пожалуйста, включите их в ваше решение -

  • Какова сложность вашей программы (включая базовый анализ, если не тривиальный)

  • длина символа

  • окончательный расчетный балл

Это мой первый вопрос CodeGolf, поэтому, если в вышеприведенных правилах есть ошибка или лазейка, пожалуйста, укажите на них.


5
Это очень похоже на codegolf.stackexchange.com/questions/5977/… .
Гарет

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 * log log 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)(из-за плотности простых чисел).
Угорен

Если мой счет нужно исправить, пожалуйста, исправьте это для меня, у меня все еще нет хорошего понимания системы начисления очков.
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)).

Об оценке сложности

Я измерил время выполнения для простых чисел 100 и 200 000, затем рассчитал 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, соответственно. Это не может быть правдой. Оценка на диапазоне 200к / 100к дает 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. Также я, видимо, не могу использовать калькулятор, поэтому мой результат не так ужасен, как я думал. (используя сложность для базового пробного деления, как показано в источнике ниже).

В соответствии с Will Ness нижеприведенное не является полной программой на Haskell (на самом деле она основана на REPL). Ниже приведена более полная программа с псевдоситом (при импорте фактически сохраняется символ, но мне не нравится импорт в кодовом гольфе).

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

Эта версия, несомненно, (п ^ 2). Алгоритм - всего лишь гольф-версия наивного "сита", как видно здесь Old ghci 1 liner

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)), если Хаскелл использует наивное деление, а не, как я предположил, Карацубу)
Питер Тейлор

Нет, потому что это дает мне ужасную оценку: /. Но я уверен, что ты прав. Это просто выглядело как пробное деление, и это временная сложность деления проб (возможно, в соответствии с моим плохим пониманием чтения, возможно, неверного источника), поэтому я выбрал это. Пока я назову свой счет NaN, это кажется безопасным.
Walpen

Я предполагаю (мой 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);}}}}

Вариант scriptcs, 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);}

Если вы устанавливаете скриптки, вы можете запустить его.

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 это очень медленно. Потребовалось около 27 минут, чтобы запустить N = 5000; Считай себя предупрежденным.

Алгоритм:

Это использует основной рекурсивный алгоритм для поиска простых чисел. Учитывая список всех простых чисел от 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 выдаст ошибку, когда достигнет конца. 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 () выше. Операторы «If» интересно реализовать в 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 символов, прошу прощения за отсутствие уведомлений
Optimus

Я полагаю, что мы можем предположить, что вход для этой программы является «исходным»; т. е. вводом является цифра сразу после IF K=(поэтому длина программы не будет включать цифру). В существующем состоянии программа печатает первые n простых чисел, не включая 2, которые можно исправить, добавив ?2в начале и изменив K=...на K=...-1. Программа также может быть golfed немного, беря пространства из состояния J=2 TO, J=0 THEN, K=...-1 THENи пути удаления отступов. Я считаю, что это приводит к программе из 96 символов.
Res

3

Scala 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% в этом диапазоне, но на самом деле для формулы оценки мы не учитываем постоянные факторы?

новые соображения Big-O:

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

Таким образом, для значений i от 1 до 6 => NPrimes (10 ^ i) выполняется 9399, 133768 ... раз внешний цикл.

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

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

O: (n: Int) Long

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

ns: List [Long] = List (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

Но я не уверен, насколько близко я могу приблизиться с моей O-функцией к наблюдаемым значениям.


Извините, я внес некоторые изменения в формулировку проблемы, чтобы уменьшить двусмысленность, связанную со сложностью (я уверен, что ваше решение не сильно изменится)
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

Ruby 66 символов, O (n ^ 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(найденные простые числа) не будут равны 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 + эпсилон))

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++;}}'

Python - 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

BASH, 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графического окна России (вероятно, почти забытая особенность). ;-)

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 '14

Простите, но что вы имеете в виду?
BB94

за награду (фииииииииилерррр)
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, должно возвращаться 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))]))

Он хранит список найденных простых чисел и проверяет делимость каждого следующего числа на уже найденные простые числа. Более того, он проверяет только до квадратного корня проверяемого числа, поскольку этого достаточно.

Ungolfed:

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