Кодировать целое число

33

Дано целое положительное число n > 2. Мы конвертируем его в массив следующим образом:

  1. Если оно равно 2 возвращать пустой массив
  2. В противном случае создайте массив всех nпростых факторов, отсортированных по возрастанию, затем каждый элемент замените своим индексом в последовательности простых чисел и, наконец, преобразуйте каждый элемент в массив.

Например, давайте преобразовать число 46в массив. Во-первых, преобразуйте его в массив основных факторов:

[2, 23]

Число 23- это 9простое число, поэтому замените его 2на пустой массив и 23на [9]. Массив теперь становится:

[[], [9]]

Главными факторами 9являются, 3а 3, значит:

[[], [3, 3]]

Сделайте то же самое для обоих 3:

[[], [[2], [2]]]

И наконец:

[[], [[[]], [[]]]]

Теперь, чтобы закодировать его, мы просто заменяем каждую открытую скобку на 1и каждую закрывающую скобку 0, затем удаляем все конечные нули и сбрасываем один 1с конца. Это наше двоичное число. Используя приведенный выше пример:

[ ] [ [ [ ] ] [ [ ] ] ]

| | | | | | | | | | | |
| | | | | | | | | | | |
V V V V V V V V V V V V

1 0 1 1 1 0 0 1 1 0 0 0

Теперь просто отбросьте последние три нуля и последний 1. Номер становится 10111001который есть185 в десятичной системе . Это ожидаемый результат. Обратите внимание, что в преобразование массива в двоичные скобки основного массива не включены.

вход

Целое положительное число nбольше чем 2.

Выход

Закодированное целое число n.

Правила и формат ввода-вывода

  • Стандартные правила применяются.
  • Входные данные могут быть строкой или числом (но в случае строки они должны быть в базе 10).
  • Вывод может быть строкой или числом (но в случае строки это должно быть в базе 10).
  • Это , выигрывает самый короткий ответ в байтах!

Контрольные примеры

Больше тестов по запросу.

3 ---> 1
4 ---> 2
5 ---> 3
6 ---> 5
7 ---> 6
8 ---> 10
9 ---> 25
10 ---> 11
10000 ---> 179189987
10001 ---> 944359
10002 ---> 183722
10003 ---> 216499
10004 ---> 2863321
10005 ---> 27030299
10006 ---> 93754
10007 ---> 223005
10008 ---> 1402478

песочница

H.PWiz
источник
Вы должны удалить контрольный пример с, 2так как представления не обязаны обрабатывать его.
Мистер Кскодер
4
Языки Rip, которые не имеют встроенных встроенных модулей.
Мистер Кскодер
3
@Павел. «[...] создать массив всех простых факторов n, отсортированных по возрастанию»
1
@Quelklef. Я работал над реализацией ATP (просто для удовольствия, ничего серьезного) и пытался как-то представить каждое число, используя вложенные массивы. Итак, эта кодировка - первая идея, которая мне пришла в голову.
1
@WheatWizard. Я не имею в виду точный математический смысл слова целое . Я собираюсь оставить это. :-)

Ответы:

12

Шелуха , 35 31 30 29 26 25 24 22 20 19 15 байт

-7 байт благодаря @Zgarb!

Сохранено лишние 4 байта, косвенно, благодаря Zgarb

ḋhΣhgφṁȯ`Jḋ2⁰ṗp

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

Explaination

     φ             -- Define a recursive function which calls itself ⁰ and is applied to an Integer
      ṁ       p    -- map then concatenate over its prime factors
             ṗ     --   return their indices into the primes
            ⁰      --   and then recur, applying ⁰ to that number
       ȯ`Jḋ2       --   then surround it between the list [1,0] (binary 2)
    g              -- group adjacent equal elements
   h               -- drop last element (trailing 0s)
  Σ                -- concatenate
 h                 -- drop the last element
ḋ                  -- interpret as base 2
H.PWiz
источник
Я думаю, что это должно работать на 27 байтов, но время вывода
TIO
2
Неважно, 25 байт и работает. Наконец, пример использования для φ, с фиксированной точкой лямбда!
Згарб
Ничего себе, я никогда не понимал его варианты использования, до сих пор
H.PWiz
Мы добавили lambdas с фиксированной точкой в ​​Husk очень рано, до того как были реализованы многострочные программы. Я думаю, мы думали, что они будут лучшим способом справиться с рекурсией. Но они довольно неясны, за исключением сохранения одного байта в особых случаях, подобных этому.
Згарб
`:0:1может быть `Jḋ2.
Згарб
7

Желе ,  22 20  19 байт

-1 спасибо Эрику Аутгольферу (хвостовые нули с обеих сторон t, а не справаœr )

ÆfÆC$ÐLŒṘO%3ḟ2Ḋt0ṖḄ

Монадическая ссылка, принимающая целое число больше 2 и возвращающая целое число больше 0 (2 также возвращает 0 в соответствии с исходной спецификацией).

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

Как?

Это почти точно повторяет данное описание, просто с некоторыми порядковыми манипуляциями для создания двоичного массива ...

ÆfÆC$ÐLŒṘO%3ḟ2Ḋt0ṖḄ - Link: number n (>=2)
     ÐL             - loop until no more changes occur:
    $               -   last two links as a monad:
Æf                  -     prime factorisation (includes duplicates & vectorises)
  ÆC                -     count primes less than or equal (vectorises)
                    -   ...note for entries of 2 this yields [1]
                    -      then for entries of 1 it yields [], as required
       ŒṘ           - get a Python representation - just like in the OP,
                    -    something like: "[[], [[[]], [[]]]]" (for an input of 46)
         O          - convert to ordinals e.g. [91,91,93,44,32,91,91,91,93,93,44,32,91,91,93,93,93,93]
          %3        - modulo by 3         e.g. [ 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 0, 0]
            ḟ2      - filter discard twos e.g. [ 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0]
              Ḋ     - dequeue             e.g. [ 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0]
               t0   - strip zeros         e.g. [ 1, 0, 1, 1, 1, 0, 0, 1, 1]
                 Ṗ  - pop                 e.g. [ 1, 0, 1, 1, 1, 0, 0, 1]
                  Ḅ - binary to decimal   e.g. 185
Джонатан Аллан
источник
Ах да, я определенно могу; Спасибо.
Джонатан Аллан
6

Python 2 , 212 177 байт

lambda n:int(g(n).rstrip("0")[1:-1],2)
g=lambda n:"1%s0"%"".join(map(g,p(n)))
def p(n,i=0,j=1):
 while n>1:
  j+=1;P=q=1;exec"P*=q*q;q+=1;"*~-j;i+=P%q
  while n%j<1:yield i;n/=j

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

Недостаток простых встроенных функций действительно вредит количеству байтов, и это приводит к превышению времени на TIO с большими простыми числами. Использование XNOR «s проверка простоты.


Python 2 + gmpy2 , 175 байт

lambda n:int(g(n).rstrip("0")[1:-1],2)
g=lambda n:"1%s0"%"".join(map(g,p(n)))
def p(n,i=0,j=1):
 while n>1:
  j+=1;i+=is_prime(j)
  while n%j<1:yield i;n/=j
from gmpy2 import*

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

Эта версия не работает в более длительных тестовых случаях (т. Е. 10000 - 10008).

notjagan
источник
5

Mathematica, 125 119 байт

Flatten[#//.{{1}->{1,0},a_/;a>1:>{1,List/@PrimePi[Join@@Table@@@FactorInteger@a],0}}]/.{1,d__,1,0..}:>{d}~FromDigits~2&

Использует немного другой подход; преобразует простые индексы в {1, index, 0}, а 2 в {1, 0}.

Попробуйте на Wolfram Sandbox

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

f = Flatten[ ...

f[10008]

1402478

Юнг Хван Мин
источник
Оригинальный ответ работает на 10008, но это не удается
Келли Lowder
1
@KellyLowder Исправлено!
JungHwan Мин.
2

J, 74 73 66 байт

3 :'#.(}.~ >:@i.&1)&.|.2+}.;<@(_2,~_1,[:>:[:_1&p:q:) ::<"0@;^:_ y'

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

Это настоящий беспорядок, который, безусловно, нуждается в дальнейшей игре в гольф (например, удаление явного определения функции). Я думаю, что бокс, которым я занимался, - это, в частности, то, что поднимает bytecount, так как я действительно не знаю, что я там делаю (было много проб и ошибок). Кроме того, я почти уверен, что есть некоторые встроенные модули, о которых я забыл (например, я чувствую, что, _2,~_1,вероятно, имеет встроенные модули ).

Объяснение (без золота)

преамбула

Расслабьтесь, потому что это не будет коротким объяснением. По иронии судьбы, лаконичный язык сочетается с многословным человеком.

Я буду разбивать это на несколько функций

encode  =. 3 : '<@(_2,~_1, [: >: [: _1&p: q:) ::<"0@;^:_ y'
convert =. 3 : '2 + }. ; y'
drop    =. (}.~ >:@i.&1)&.|.
decode  =. #.
  • encode кодирует целое число, используя _1 и _2 вместо [и]
  • convert преобразует список _1 и _2 в список 1 и 0
  • drop отбрасывает последние 1 и завершающие нули
  • decode конвертирует из двоичного списка в число

Я буду идти через образец вызова для 46, который выражается в формате ungolfed сделано

   decode drop convert encode 46
185

шифровать

Здесь есть много чего объяснить.

3 : '<@(_2,~_1, [: >: [: _1&p: q:) ::< "0@;^:_ y'
                                           ^:_      Do until result converges
                                          ;          Raze (remove all boxing)
                                       "0            For each
                               q:                     Factorize
                         _1&p:                        Get index of prime
                   >:                                 Add 1 (J zero-indexes)
            _1,                                       Prepend -1
        _2,~                                          Append -2
     <                                                Box resulting array
                                   ::                If there is an error
                                     <                Box the element

Обратите внимание, что явное определение функции 3 : '[function]'оценивает функцию, как если бы она была в REPL с правильным аргументом, заменяющим каждый экземпляр y(это означает, что я могу избежать необходимости использовать caps ( [:), atops ( @) и ats (@: ) за счет несколько байтов).

Вот как это выглядит для каждой последовательной итерации на входе 46

┌─────────┐    ┌──┬─────┬─────────┬──┐    ┌──┬──┬──┬──┬───────┬───────┬──┬──┐
│_1 1 9 _2│ => │_1│_1 _2│_1 2 2 _2│_2│ => │_1│_1│_2│_1│_1 1 _2│_1 1 _2│_2│_2│ =>
└─────────┘    └──┴─────┴─────────┴──┘    └──┴──┴──┴──┴───────┴───────┴──┴──┘

┌──┬──┬──┬──┬──┬─────┬──┬──┬─────┬──┬──┬──┐    
│_1│_1│_2│_1│_1│_1 _2│_2│_1│_1 _2│_2│_2│_2│ => the final iteration is just every
└──┴──┴──┴──┴──┴─────┴──┴──┴─────┴──┴──┴──┘    value in its own box

В этой функции используется invalid ( ::) для вложения значений в «скобки» (здесь используются скобки -1 и -2). По сути, каждый раз, когда мы разлагаем и преобразуем в индексы простых чисел, добавляется _1 и добавляется _2, которые действуют как скобки. Когда функция вызывается для этих элементов, она просто возвращает их как есть, так q:как при попытке факторизации отрицательного числа произойдет ошибка. Это также повезло , что q:это не ошибка при попытке факторизовать 1 , а вместо этого возвращает пустой массив (по желанию).

Конвертировать

3 : '2 + }. ; y'
            ;     Raze (remove boxing)
         }.       Behead (remove head)
     2 +          Add 2

Конвертировать намного проще. Он просто удаляет весь бокс, а также первый элемент, а затем преобразует все в 1 и 0 (просто добавив 2)

Капля

(}.~ >:@i.&1)&.|.
             &.|.  Reverse, apply the left function, and then undo
 }.~ >:@i.&1        Drop the leading zeroes and first 1
        i.&1         Index of first one
     >:              Add 1
 }.~                 Drop

Это переворачивает список, находит первое и затем сбрасывает все значения до этого, затем снова переворачивает список.

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

Декодирование - это встроенная функция, #.которая берет список из 1 и 0 и преобразует его в двоичное число.

капуста
источник
2

Сетчатка , 244 227 225 байт

+%(G`
\d+
$*0¶$&$*
+`^00(0+)
0$1¶$0
A`^(00+?)\1+$
^0+
$0;1
+`(1+)¶0+(?=¶)
$0;1$1
+`¶(11+?)(\1)*$
¶$1¶1$#2$*1
1$

m`^11$
[]
m`^1+
[¶$.0$*0¶]
+s`(0+);(1+)(.+¶)\1¶
$1;$2$3$2¶
0+;1+¶

)`1+
$.0
T`[]¶`10_
10+$

1
01
+`10
011
^0+

1

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

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

Объяснение:

+%(G`                Repeatedly apply on each line:
\d+                      If the line is a number, convert it to unary 0s and 1s
$*0¶$&$*
+`^00(0+)                Generate all prefixes of the zeros greater than 1
0$1¶$0
A`^(00+?)\1+$            Remove non-prime strings of zeros
^0+                      Index the first zero set (00) as 1
$0;1
+`(1+)¶0+(?=¶)           Index the rest of the zeroes as their prime index
$0;1$1
+`¶(11+?)(\1)*$          Compute prime factors of input value
¶$1¶1$#2$*1
1$                       Remove the 1 factor (not really prime)

m`^11$                   Turn all 2 prime factors to []
[]
m`^1+                    Surround all non-2 prime factors in brackets
[¶$.0$*0¶]
+s`(0+);(1+)(.+¶)\1¶     Convert non-2 prime factors to their index
$1;$2$3$2¶
0+;1+¶                   Remove the list of primes

)`1+                     Return all primes back to decimal ready to be repeated
$.0
T`[]¶`10_            Then convert all [ to 1 and ] to 0, and remove linefeeds
10+$                 Remove the final 1 and trailing zeroes

1                    Convert from binary to unary
01
+`10
011
^0+

1                    Convert from unary to decimal
PunPun1000
источник
1

Haskell , 162 160 155 байтов

sum.zipWith((*).(2^))[0..].tail.snd.span(<1).(r%)
r=zip[1..][x|x<-[2..],all((>0).mod x)[2..x-1]]
_%1=[]
((i,q):p)%n|mod n q<1=r%div n q++0:r%i++[1]|1<3=p%n

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

Объяснение:

r=zip[1..][x|x<-[2..],all((>0).mod x)[2..x-1]] определяет бесконечный список наборов простых чисел и их индексов: [(1,2),(2,3),(3,5),(4,7),(5,11),(6,13), ...] .

Функция (%)берет этот список rи число nи преобразует число в представление обращенного массива факторов. Это делается пошагово, rпока мы не найдем простое число, которое делит n. Затем мы рекурсивно определяем представление индекса этого простого числа и заключаем его в 0и 1и добавляем представлениеn это простое число.

Для n=46этого получается список, [0,0,0,1,1,0,0,1,1,1,0,1]из которого затем удаляются ведущие нули ( snd.span(<1)) и следующий 1( tail). Затем список преобразуется в десятичное число с помощью поэлементного умножения с перечнем полномочий два и суммирования полученного списка: sum.zipWith((*).(2^))[0..].

Laikoni
источник
0

JavaScript, 289 байт

Байты - это сумма кода JavaScript без разрывов строк после запятых (которые вставляются только для лучшего форматирования и удобочитаемости) (256 байтов) и дополнительные символы для переключения командной строки, что требуется при использовании Chrome (33 байта).

'use strict'
var f=(n,i=2,r=[])=>n>1?n%i?f(n,i+1,r):f(n/i,i,r.concat(i)):r,
c=(p,r=1,i=2)=>i<p?f(i)[1]?c(p,r,i+1):c(p,r+1,i+1):r-1?f(r).map(h):[],
h=a=>c(a),
s=a=>a.reduce((r,e)=>r+s(e),'1')+' ',
o=i=>+('0b'+s(f(i).map(h)).trim().replace(/ /g,'0').slice(1,-1))

И более длинная, лучше читаемая версия:

'use strict';
const f = (n,i=2,r=[]) => n>1 ? n%i ? f(n,i+1,r) : f(n/i,i,r.concat(i)) : r;
const c = (p,r=1,i=2) => i<p ? f(i)[1] ? c(p,r,i+1) : c(p,r+1,i+1) : r-1 ? f(r).map(h) : [];
const h = i => c(i);
const s = a => a.reduce((r,e) => r+s(e),'1')+' ';
const o = i => +('0b'+s(f(i).map(h)).trim().replace(/ /g,'0').slice(1,-1));

Несколько кратких объяснений:

f является чисто функциональным алгоритмом хвостовой рекурсивной факторизации

cподсчитывает, в каком месте rпростое число pвстречается в последовательности простых чисел и возвращает либо [](если p=2и r=1), либо факторизирует и далее обрабатывает rс помощью рекурсии.

hэто небольшая вспомогательная функция, которая, к сожалению, необходима, так как mapвызывает предоставленную функцию numberOfCurrentElementв качестве второго и wholeArrayтретьего аргумента, таким образом переопределяя значения по умолчанию, предоставленные, cесли мы передадим эту функцию напрямую (мне потребовалось некоторое время, чтобы разобраться с этой ловушкой; замена hпо определению будет на несколько байт длиннее).

sпреобразует сгенерированный массив в строку. Мы используем blankвместо того, 0чтобы мы могли использовать trim()в o.

oявляется функцией, которая вызывается с входным значением, iкоторое возвращает выходные данные. Он генерирует двоичное строковое представление, требуемое спецификацией, и преобразует его в (десятичное) число.

Изменить: Chrome должен быть запущен chrome --js-flags="--harmony-tailcalls"для включения оптимизации хвостовой рекурсии (см. Https://v8project.blogspot.de/2016/04/es6-es7-and-beyond.html ). Это также требует использования строгого режима.

Следующий тест показывает, что вычисление немного медленное для некоторых значений (самое длинное - более шести секунд для 10007моего компьютера). Интересно, что без оптимизации хвостовой рекурсии вычисление выполняется намного быстрее (примерно в 5 раз), когда нет переполнения стека.

for (let i=3; i<=10008; i==10 ? i=10000 : ++i) {
    let time = new Date().getTime();
    let val = o(i);
    time = new Date().getTime() - time;
    document.write(i + ': ' + o(i) + ' (computed in ' + time + ' ms)<br>');
}
Fabian
источник
0

тинилисп , 209 байт

(load library
(d [(q((N)(map(q((P)([(length(filter prime?(1to P))))))(reverse(prime-factors N
(d B(q((L)(c 1(insert-end 0(foldl concat(map B L
(d T(q((N)(if(mod N 2)(/ N 2)(T(/ N 2
(q((N)(T(from-base 2(t(B([ N

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

Версия для игры в гольф

Вот код, который у меня был до того, как я начал играть в гольф:

(load library)

(def prime-index
 (lambda (P)
  (length (filter prime? (1to P)))))

(def to-list
 (lambda (N)
  (map to-list
   (map prime-index
    (reverse (prime-factors N))))))

(def to-bits
 (lambda (L)
  (cons 1
   (insert-end 0
    (foldl concat
     (map to-bits L))))))

(def trim
 (lambda (N)
  (if (mod N 2)
   (div2 N 2)
   (trim (div2 N 2)))))

(def encode
 (lambda (N)
  (trim
   (from-base 2
    (tail (to-bits (to-list N)))))))
DLosc
источник
0

05AB1E , 18 байт

ΔÒ.Ø>}¸»Ç3%2K0ܨ2β

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

Объяснение:

Δ    }       # loop until a fixed point
 Ò           # replace each number with its prime factorization
  .Ø>        # replace each prime with its 1-based index
¸»           # after the loop: join to a string
  Ç          # get ASCII value of each character
   3%        # modulo 3 (maps '[' to 1, ']' to 0, ' ' to 2, ',' to 2)
     2K      # remove 2s
       0Ü    # trim trailing 0s
         ¨   # remove the last 1
          2β # parse as base 2
Grimmy
источник