Нумерація сторінок у стилі xkcd


65

У книзі Рандалла Манро "xkcd, том 0" використовується досить непарна система числення для номерів сторінок. Перші кілька номерів сторінок є

1, 2, 10, 11, 12, 20, 100, 101, 102, 110, 111, 112, 120, 200, 1000, 1001, ...

Це виглядає як троичной, але зауважив , що він скаче від 20прямо 100від 120до 200і від 200до 1000. Один із способів визначення цієї послідовності полягає в тому, щоб сказати, що вона перераховує всі потрійні числа, які містять не більше одного, 2а 1після цього немає 2. Ви можете знайти це на OEIS у записі A169683 . Ця система числення відома як перекос двійкової .

Ваше завдання - знайти представлення даного додатного цілого числа Nв цій системі числення.

Ви можете написати програму або функцію, взявши введення через STDIN (або найближчу альтернативу), аргумент командного рядка або аргумент функції та вивівши результат через STDOUT (або найближчу альтернативу), значення повернення функції або параметр функції (out).

Виведенням може бути рядок, число з десятковим поданням, рівним перекосу двійкового подання, або список цифр (у вигляді цілих чи знаків / рядків). Ви не повинні повертати провідні нулі.

Це кодовий гольф, тому найкоротша відповідь (у байтах) виграє.

Веселий факт: насправді є деяка заслуга цієї системи числення. Збільшуючи число, ви завжди будете змінювати щонайбільше дві суміжні цифри - вам ніколи не доведеться переносити зміну через усе число. З правильним поданням, що дозволяє збільшувати O (1).

Випробування

1 => 1
2 => 2
3 => 10
6 => 20
7 => 100
50 => 11011
100 => 110020
200 => 1100110
1000 => 111110120
10000 => 1001110001012
100000 => 1100001101010020
1000000 => 1111010000100100100
1048576 => 10000000000000000001

1000000000000000000 => 11011110000010110110101100111010011101100100000000000001102

Я дам нагороду за найкоротший відповідь, який може вирішити останній тестовий випадок (та будь-який інший вклад подібної величини, тому не думайте про жорстке кодування) менше ніж за секунду.

Табло лідерів

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

Щоб переконатися, що ваша відповідь відображається, будь ласка, почніть свою відповідь із заголовка, використовуючи наступний шаблон Markdown:

# Language Name, N bytes

де Nрозмір вашого подання. Якщо ви покращите свій рахунок, ви можете зберегти старі бали у заголовку, прокресливши їх. Наприклад:

# Ruby, <s>104</s> <s>101</s> 96 bytes

<script>site = 'meta.codegolf'; postID = 5314; isAnswer = true; QUESTION_ID = 51517</script><script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script><script>jQuery(function(){var u='https://api.stackexchange.com/2.2/';if(isAnswer)u+='answers/'+postID+'?order=asc&sort=creation&site='+site+'&filter=!GeEyUcJFJeRCD';else u+='questions/'+postID+'?order=asc&sort=creation&site='+site+'&filter=!GeEyUcJFJO6t)';jQuery.get(u,function(b){function d(s){return jQuery('<textarea>').html(s).text()};function r(l){return new RegExp('<pre class="snippet-code-'+l+'\\b[^>]*><code>([\\s\\S]*?)</code></pre>')};b=b.items[0].body;var j=r('js').exec(b),c=r('css').exec(b),h=r('html').exec(b);if(c!==null)jQuery('head').append(jQuery('<style>').text(d(c[1])));if (h!==null)jQuery('body').append(d(h[1]));if(j!==null)jQuery('body').append(jQuery('<script>').text(d(j[1])))})})</script>


32
Я мав цю книжку з моменту її виходу, і ніколи не помічав нумерацію сторінок.
Олексій А.

2
@AlexA. У мене він є на моєму Kindle, де ви не можете зробити жодної цікавої нумерації сторінок.
LegionMammal978

21
@ LegionMammal978: Трагічне.
Олексій А.

1
@ SuperJedi224 Консенсусу, здається, немає , так що вибачте (я б зробив виняток з консенсусу, якби це був єдиний вид вводу, з яким можна обробляти вашу мову, але, схоже, це не так).
Мартін Ендер

4
Це нагадує мені про те, як я колись рахував, коли мені було 3 роки. Я аргументував: "П’ятдесяти десяти немає, тому після ста дев'яти має бути двісті". Я зрозумів свою помилку, лише побачивши різницю між 59->60і 109->110, маючи додаткові 0.
Cyoce

Відповіді:


12

Піт, 17 байт

Ljb3ye.f!-P-yZ01Q

Це дещо смішно повільно - O(output^log_2(3)). Це експоненціальна довжина введення, але не подвійна експоненціальна, як деякі відповіді на сторінці. Деякі ідеї, взяті з відповіді @ Денніса, тут .

Демонстрація.

Він використовує .fфункцію "циклу, поки не знайдено n збігів" Pyth.


32

CJam, 24 23 22 21 19 байт

ri_)2b,,W%{2\#(md}/

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

Цей код закінчується помилкою, що переходить до STDERR з інтерпретатором Java, яка дозволена відповідно до консенсусу щодо Meta .

Якщо ви спробуєте цей код у інтерпретаторі CJam , просто ігноруйте все, окрім останнього рядка виводу.

Помилку можна усунути, ціною 2 байти, попередньо 2>до W%.

Дякуємо @ MartinBüttner за те, що він грає на один байт.

Фон

Бічне подання перекосу a k ... a 0 відповідає цілому числу n = (2 k + 1 -1) a k + ... + (2 1 -1) a 0 .

Оскільки обидва (2 k -1) + ... + (2 1 -1) = 2 k + 1 - (k + 2) і (2 k -1) + ... + 2 (2 j -1) = 2 до + 1 - (2 J + 1 - 2 J + до + 1) менше , ніж 2 до + 1 -1 , значення в до до в 0 можуть бути відновлені шляхом послідовного модульного поділу на 2 K + 1 -1 , 2 к -1 тощо.

Для початку нам слід знайти значення 2 k + 1 -1 спочатку. Оскільки n становить максимум 2 (2 k + 1 -1) , ціле число n + 1 має бути строго меншим за 2 k + 2 .

Таким чином, беручи цілу частину двійкового логарифму n + 1, виходить k + 1 .

Нарешті, ми спостерігаємо, що ціле число n + 1 має ⌊log 2 (n + 1) ⌋ цифр у базі 2.

Як це працює

ri    e# Read an integer N from STDIN.
2b,   e# Push the number of binary digits of N + 1, i.e, K + 2 = log(N + 1) + 1.
,W%   e# Push the range [K+1 ... 0].
{     e# For each J in the range:
  2\# e#   J -> 2**J
  (   e#     -> 2**J - 1
  md  e#   Perform modular division of the integer on the stack (initially N)
      e#   by 2**J - 1: N, 2**J - 1 -> N/(2**J - 1), N%(2**J - 1)
}/    e#

В останніх двох ітераціях ми виконуємо модульний поділ на 1 і 0 . Перший натискає небажаний 0 на стек. Останні спроби виконання 0 0 md, які вискакують як небажані 0 s зі стека, завершуються негайно, замість того, щоб щось штовхати і скидає стек до STDOUT.


28

Python 2, 67 байт

def f(n):x=len(bin(n+1))-3;y=2**x-1;return n and n/y*10**~-x+f(n%y)

Здається, працює для даних тестових випадків. Якщо я маю на це право, це повинно бути приблизно O(place values set in output), тому це робиться останній випадок легко.

Телефонуйте як f(100). Повертає десяткове подання, яке дорівнює двійковому перекосу.

Python 3, 65 байт

def g(n,x=1):*a,b=n>x*2and g(n,x-~x)or[n];return a+[b//x,b%x][:x]

Трохи менш ефективний, але все ж логарифмічний, тому останній випадок майже миттєвий.

Телефонуйте як g(100). Повертає список цифр.


це 2andскомпілювати в 3? Я в 2 і 2and2кидає синтаксичну помилку
TankorSmash

3
@TankorSmash 2and2не буде працювати, тому що він буде проаналізований як 2 and2- спробуйте 2and 2, що має працювати, якщо ваша версія Python є достатньо новою (перевірена в Python 2.7.10)
Sp3000

О, приємно, ти маєш рацію. Навіть на 2.7.3 це працює.
TankorSmash

12

CJam, 22 21 20 байт

ri_me,3fb{0-W<1-!},=

Це підхід O (e n n) , де n - вхід. У ньому перераховані перші ⌊e п невід'ємні цілі числа в підставі 3, усуває ті , які мають 2 з або 1 с після першої 2 (якщо такі є) і вибирає N + 1 - го .

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

ri    e# Read an integer N from STDIN.
_me,  e# Push [0 ... floor(exp(N))-1].
3fb   e# Replace each integer in the range by the array of its digits in base 3.
{     e# Filter; for each array A:
  0-  e#   Remove all 0's.
  W<  e#   Remove the last element.
  1-  e#   Remove all 1's.
  !   e#   Logical NOT. Pushes 1 iff the array is empty.
},    e#   If ! pushed 1, keep the array.
=     e# Select the (N+1)th element of the filtered array.

9

Pyth, 20 байт

Jt^2hslhQ#p/=%QJ=/J2

Працює в O (журнал (вхід ())), що знаходиться за секунду для остаточного тестового випадку Базується на циклі до циклу помилок. Немає зворотного рядка.

Демонстрація.

Пояснення:

Jt^2hslhQ#p/=%QJ=/J2
                        Implicit: Q is the input.
      lhQ                          log(Q+1,2)
     slhQ                    floor(log(Q+1,2))
    hslhQ                    floor(log(Q+1,2))+1
  ^2hslhQ                 2^(floor(log(Q+1,2))+1)
 t^2hslhQ                 2^(floor(log(Q+1,2))+1)-1
Jt^2hslhQ               J=2^(floor(log(Q+1,2))+1)-1
         #              until an error is thrown:
            =%QJ        Q=Q%J
                =/J2    J=J/2
           /            The value Q/J, with the new values of Q and J.
          p             print that charcter, with no trailing newline.

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

  • Видаліть кожну цифру значення Jзі Qс =%QJ. Наприклад, якщо Q=10і J=7, Qстає 3, що відповідає бінарній перекосу, що змінюється з 110на 10. Це не впливає на першу ітерацію.
  • Змініть Jна наступне менше косове двійкове базове значення за допомогою =/J2. Це убитий розподіл на 2, зміна J=7до J=3, наприклад. Оскільки це відбувається до виведення першої цифри, Jінтилізується позиція на одну цифру вище, ніж потрібно.
  • Знайдіть фактичне значення цифри за допомогою /QJ(ефективно).
  • Роздрукуйте це значення pзамість друку за замовчуванням Pyth, щоб уникнути зворотного нового рядка.

Цей цикл буде повторюватися, поки не Jстане нульовим, після чого помилка ділення на нуль буде кинута, і цикл закінчиться.


8

ES6, 105 байт

f=n=>{for(o=0;n--;c?o+=Math.pow(3,s.length-c):o++)s=t(o),c=s.search(2)+1;return t(o);},t=a=>a.toString(3)

Використання: f(1048576)=> `" 10000000000000000001 "

Перевірте останній аргумент на власну небезпеку. Я здався через 5 секунд.

І гарненький друк з коментарями!

f=n=>{ //define function f with input of n (iteration)
    for(o=0; //define o (output value in decimal)
        n--; //decrement n (goes towards falsy 0) each loop until 0
        c?o+=Math.pow(3,s.length-c):o++) //if search finds a 2, increment output by 3^place (basically moves the 2 to the left and sets the place to 0), else ++
        s=t(o), //convert output to base 3      
        c=s.search(2)+1; //find the location of 2, +1, so a not-found becomes falsy 0.
    return t(o); //return the output in base 3
},

t=a=>a.toString(3);  //convert input a to base 3

5
Btw, неназвані функції цілком прийнятні, тому вам не потрібно f=.
Мартін Ендер

2
-16 байт:f=n=>{for(o=0;~n--;o+=c?Math.pow(3,s.length+c):1)s=o.toString(3),c=~s.search(2);return s}
nderscore

@nderscore Досить круто: D
Компас

1
-7 байт, якщо ви використовуєте ES7: замініть Math.pow(3,s.length+c)на 3**(s.length+c).
Густаво Родрігес

3
@GustavoRodrigues Я навіть не закінчив вивчати ES6! @ _ @
Компас

7

Сітківка, 55 байт

^
0a
(+`12(.*a)1
20$1
0?2(.*a)1
10$1
0a1
1a
)`1a1
2a
a
<empty line>

Здійснює введення в одинаковому режимі.

Кожен рядок повинен мати свій власний файл, але ви можете запустити код як один файл із -sпрапором. Наприклад:

> echo 11111|retina -s skew
12

Метод: Виконання приросту на введеному ряду кількість разів, починаючи з рядка 0.

Ми використовуємо такі правила нарощування:

  • якщо містить 2: ^2 -> ^12; 02 -> 12;12 -> 20
  • якщо не містить 2: 0$ -> 1$;1$ -> 2$

(Там може бути більше однієї 2в рядку, ^і $відзначає початок і кінець рядка в правилах) .

Більше інформації про Retina.


7

Ява, 154 148

n->{String s="0";for(;n-->0;)s=s.contains("2")?s.replaceAll("(^|0)2","10").replace("12","20"):s.replaceAll("1$","2").replaceAll("0$","1");return s;}

Ця відповідь має форму єдиної анонімної функції, яка приймає цілий аргумент і повертає відповідь у вигляді рядка. Нижче наведено повний клас для тестування цього рішення.

import java.util.function.Function;
public class Skew {
    public static void main(String[] args){
        Function<Integer,String> skew = n->{String s="0";for(;n-->0;)s=s.contains("2")?s.replaceAll("(^|0)2","10").replace("12","20"):s.replaceAll("1$","2").replaceAll("0$","1");return s;};

        for(String s:args){
            System.out.println(skew.apply(Integer.parseInt(s)));
        }
    }
}

5

Bash + coreutils, 52

dc -e3o0[r1+prdx]dx|grep -v 2.\*[12]|sed -n $1{p\;q}

Це грубий нападник, тому його досить повільно для більшої кількості.

Вихід:

$ ./xkcdnum.sh 1000
111110120
$ 

5

Java, 337 335 253 246 244 байт

Метод, який приймає індекс як a longі повертає результат у вигляді рядка

Використовує a longдля індексу, тому теоретично може обробити останній тестовий випадок, але я дійсно не запропонував би його.

String f(long i){List<Long>l=new ArrayList<>();l.add(0L);for(;i-->0;){int j=l.indexOf(2);if(j!=-1){l.set(j,0L);if(j==0){l.add(0,1L);}else{l.set(j-1,l.get(j-1)+1);}}else{j=l.size()-1;l.set(j,l.get(j)+1);}}String s="";for(long q:l)s+=q;return s;}

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

2
Вам не потрібні дужки у if(j == 0) виписці (чотири байти). Вам не потрібно декларувати k; можна просто використовувати jще раз (ще чотири). Ви можете використовувати загальний тип виводу (на Java 7) у своєму списку декларацій ( new ArrayList<>();) (ще 4)
durron597

4

Хаскелл, 73 72

Дякуємо @nimi за 1 байт!

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

i(2:b)=1:0:b
i[b]=[b+1]
i(b:2:c)=b+1:0:c
i(b:c)=b:i c
s=(iterate i[0]!!)

Це рішення є досить наївним підходом, який обчислює бічне число перекосу n, збільшуючи 0 nразів.


4

CJam, 24 байти

Q{0\+2a/())+a\+0a*}ri*si

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

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Фон

Збільшення числа в косому двійковому форматі можна виконати, виконавши два простих кроки:

  1. Замініть можливий 2 на 0 .

  2. Якщо 2 було замінено, збільште цифру вліво.

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

Як це працює

Q     e# Push an empty array.
{     e# Define an anonymous function:
  0\+ e#   Prepend a 0 to the array.
  2a/ e#   Split the array at 2's.
  (   e#   Shift out the first chunk of this array.
  )   e#   Pop the last digit.
  )+  e#   Increment it and append it to the array.
  a\+ e#   Prepend the chunk to the array of chunks.
  0a* e#   Join the chunks, using [0] as separator.
      e#   If there was a 2, it will get replaced with a 0. Otherewise, there's
      e#   only one chunk and joining the array dumps the chunk on the stack.
}     e#
ri*   e# Call the function int(input()) times.
si    e# Cast to string, then to integer. This eliminates leading 0's.

4

VBA, 209 147 142 байт

Sub p(k)
For i=1To k
a=StrReverse(q)
If Left(Replace(a,"0",""),1)=2Then:q=q-2*10^(InStr(a,2)-1)+10^InStr(a,2):Else:q=q+1
Next
msgbox q
End Sub

Моя математика неефективна, і мій гольф може використовувати роботу. Але це моя перша спроба PoG, і я подумав, що спробую це. Сорт брутального способу, хоча.

Це просто підрахунок на 1, якщо остання цифра не є 2, а кроки назад на 2 і стрибки вперед 10. Плюс кінцеві 0.

Це перестає працювати на 65534, оскільки VBA наполягає на тому, щоб дати висновок у науковій нотації, але логіка повинна працювати добре для ще більших цифр

З нетерпінням чекаючи пропозицій з гольфу, VBA не дуже приємний для гольфу, але він не часто представлений, і я думаю, що він може перемогти Java на довжину.

Edit1: Дякую Ману за те, що допомогли відголити 62 байти

Edit2: перевернути debug.printдля msgboxяк вихід. Збережено 5 байт


1
Ви можете зняти дужки з Debug.Print (q). Також ви можете видалити більшу частину пробілів (редактор поверне їх назад, але вони не потрібні). Вам не потрібно декларувати k as Long, просто напишіть k. Це буде змінна типу Variant, і код все одно буде працювати. За допомогою цих порад вам слід перейти до ~ 165 байт.
CommonGuy

Ще кілька думок: Перший і останній аргумент ви можете оминути InStr, вони необов’язкові. Trim()не потрібно, оскільки у вас немає простору пробілів. Якщо правильно застосовано, я дістаю до 147 байт .
CommonGuy

1
Дякую за допомогу Ману, одне швидке запитання, вихід повинен бути стандартним результатом. Я не впевнений, що це було б у VBA. debug.print qбуде стандартний вихід? msgbox qкоротше, але знову ж таки здається, що це не зовсім стандартний вихід. Sheet1.cells(1,1)Здається, типовий вихід, але передбачає його виконання в excel. Я просто не зовсім впевнений, наскільки суворий код-гольф стосується подібних речей.
JimmyJazzx

Вітаю MsgBox!
CommonGuy

4

Javascript ES6, 99 86 78 76 72 символів

f=n=>{for(s="1";--n;s=s.replace(/.?2|.$/,m=>[1,2,10][+m]||20));return s}

// Old version, 76 chars:
f=n=>{for(s="1";--n;s=s.replace(/02|12|2|.$/,m=>[1,2,10][+m]||20));return s}

// Old version, 86 chars:
f=n=>{for(s="1";--n;s=s.replace(/(02|12|2|.$)/,m=>[1,2,10,,,,,,,,,,20][+m]));return s}

// Old version, 99 chars:
f=n=>{for(s="1";--n;s=s.replace(/(^2|02|12|20|.$)/,m=>({0:1,1:2,2:10,12:20,20:100}[+m])));return s}

Тест:

;[1,2,3,6,7,50,100,200,1000,10000,100000,1000000,1048576].map(f) == "1,2,10,20,100,11011,110020,1100110,111110120,1001110001012,1100001101010020,1111010000100100100,10000000000000000001"

Веселий факт: насправді є деяка заслуга цієї системи числення. Збільшуючи число, ви завжди будете змінювати щонайбільше дві суміжні цифри - вам ніколи не доведеться переносити зміну через усе число. З правильним поданням, що дозволяє збільшувати O (1).

Дякую за факт - це основа мого рішення :)


Як я можу залишити непотрібні дужки в регексе? o_O
Qwertiy

3

Октава, 107 101 байт

Має бути O (log n), якщо я вважаю, що це правильно ...

function r=s(n)r="";for(a=2.^(uint64(fix(log2(n+1))):-1:1)-1)x=idivide(n,a);r=[r x+48];n-=x*a;end;end

Симпатичний друк:

function r=s(n)
  r="";
  for(a=2.^(uint64(fix(log2(n+1))):-1:1)-1)
    x=idivide(n,a);
    r=[r x+48];
    n-=x*a;
  end
end

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

Результат (я включаю, 1e18 - 1щоб показати, що я можу зробити це точно, і останній набір результатів показує, скільки часу потрібно для обчислення цього значення):

octave:83> s(uint64(1e18))
ans = 11011110000010110110101100111010011101100100000000000001102

octave:84> s(uint64(1e18)-1)
ans = 11011110000010110110101100111010011101100100000000000001101

octave:85> tic();s(uint64(1e18)-1);toc()
Elapsed time is 0.0270021 seconds.

3

T-SQL, 221 189 177 байт

EDIT: Оригінальні версії цього коду давали б неправильний вихід для деяких чисел, це було виправлено.

З кожним запитом тут просто додайте число для обчислення перед першою комою.

Всі знають, що T-SQL - найкраща мова для гольфу. Ось версія, яка обчислить навіть останній тестовий випадок. На машині, на якій я її тестував, вона забігала за секунду, мені було б цікаво подивитися, як вона працює для всіх інших.

DECLARE @ BIGINT=,@T VARCHAR(MAX)='';WITH M AS(SELECT CAST(2AS BIGINT)I UNION ALL SELECT I*2FROM M WHERE I<@)SELECT @T += STR(@/(I-1),1),@%=(I-1)FROM M ORDER BY I DESC SELECT @T

І ось це знову, але читабельно:

DECLARE 
    @ BIGINT=,
    @T VARCHAR(MAX)='';

WITH M AS
(
    SELECT
        CAST(2 AS BIGINT) I

    UNION ALL

    SELECT I * 2
    FROM M
    WHERE I < @
)

SELECT 
    @T+=STR(@/(I-1),1),
    @%=(I-1)
FROM M 
ORDER BY I DESC

SELECT @T

Якщо я використовую лише вставки, це може бути трохи коротше, виходить у 157 байт:

DECLARE @ INT=,@T VARCHAR(MAX)='';WITH M AS(SELECT 2I UNION ALL SELECT I*2FROM M WHERE I<@)SELECT @T+=STR(@/(I-1),1),@%=(I-1)FROM M ORDER BY I DESC SELECT @T

І ще раз, читабельніше:

DECLARE 
    @ INT=,
    @T VARCHAR(MAX)='';

WITH M AS
(
    SELECT
        2I

    UNION ALL

    SELECT 
        I * 2
    FROM M
    WHERE I < @
)

SELECT 
    @T+=STR(@/(I-1),1),
    @%=(I-1)
FROM M 
ORDER BY I DESC

SELECT @T

Пам'ятайте @, що це дійсний ідентифікатор в sql, і ви, швидше за все, можете втекти, з Char(8000) яким все-таки дешевше, ніж nvarchar (max). Ви також можете конвертувати charзамість varcharабо використовувати strфункцію.
Майкл Б

@MichaelB О, я думав, що використав @, нерозумно мене. CHAR(8000)Рада досить добре, я спробую це. Я, здається, завжди забуваю про існування STR()подяки за голови вгору.
PenutReaper

насправді не допомагає. Однак ви можете переписати частину після CTE у ::, select @t=concat(@t,@/i)яка має бути меншою. Потрібен, хоча, sql2012
Майкл Б

@MichaelB ах. CONCAT, Я в 2008 році. Тому я не можу перевірити його без використання скрипки SQL зараз. Хоча гарний дзвінок.
PenutReaper

3

Код машини Тьюрінга, 333 293 байти

Я використовую кодування, як тут використовується .

Ця машина використовує 9 станів та 11 кольорів.

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

0 _ _ l 1
0 * * r 0
1 9 8 l 2 
1 8 7 l 2
1 7 6 l 2
1 6 5 l 2
1 5 4 l 2
1 4 3 l 2
1 3 2 l 2
1 2 1 l 2
1 1 0 l 2
1 0 9 l 1
1 _ _ r 8
2 _ _ l 3
2 * * l 2
3 _ 1 r 4
3 * * l 5
4 _ _ r 0
4 * * r 4
5 * * l 5
5 _ _ r 6
6 _ _ l 7
6 2 0 l 7
6 * * r 6
7 _ 1 r 4
7 0 1 r 4
7 1 2 r 4
8 _ _ * halt
8 * _ r 8

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


2

Perl, 66 байт

Номер повинен бути введений через STDIN.

$_=1;$c=<>;s/(.*)(.?)2(.*)/$1.$2+1 .$3.0/e||$_++while(--$c);print;

Чи можете ви пояснити, як працює ваше рішення? Я не розумію , як вам потрібно (.?)в $2так (.*)в $1повинен бути жадібним і отримати цей символ першої. Але якщо його видаляють, код більше не дає правильних результатів! До речі, вам не потрібен фінал ;.
CJ Dennis

@CJDennis Дякую за збережений байт У всякому разі,. отримає цифру, що надходить безпосередньо перед двома, якщо там немає цифри (наприклад, 20). У таких випадках, як 120 або 10020, такі групи регулярних виразів: () (1) 2 (0) і (10) (0) 2 (0). Потім перша група просто ігнорується, друга група (яка завжди або одна цифра, якщо це можливо, або порожня), збільшується, а третя група (завжди складається з нулів) ігнорується і додається нуль. Я просто використав запис OEIS в якості керівництва для цього регулярного вибору.
frederick

Я отримав свій код до 53 байт: $c=<>;s/(.*)2(.*)/$1+1 .$2.0/e||$_++while($c--);print. Я мав рацію, (.?)ніколи нічого не захоплював.
CJ Dennis

Можна оптимізувати до $_=1;$c=<>;s/(.?)2/1+$1.0/e||$_++while(--$c);print, що становить 50 байт. .*на початку чи в кінці можна оптимізувати, якщо просто замінити його початковим текстом. Також немає підстав додавати 0 наприкінці, оскільки в оригіналі завжди є лише нулі $3.
Thraidh

2

Pyth, 19 байт

m/=%Qtydtd^L2_SslhQ

Логарифмічна складність. Легко закінчується за необхідну кількість часу. Виведіть у вигляді списку цифр.

Демонстрація .


2

Perl, 84 70 67 байт

$n=<>;$d*=2while($d++<$n);$_.=int($n/$d)while($n%=$d--,$d/=2);print

Не дуже гофрований, покращуючись, але це працює дуже швидко!

Пропозиція Денніса зменшує його до 51 (50 байт + -p перемикач)

$d*=2while$d++<$_;$\.=$_/$d|0while$_%=$d--,$d/=2}{

Він повинен називатися так, perl -p skew_binary.pl num_list.txtде num_list.txtміститься один рядок з номером для кодування на ньому.


@frederick ми на межі наших місць в очікуванні 2.
Роберт Грант

@RobertGrant Він розіграв свій коментар від двох речей до однієї речі!
CJ Dennis

Дві речі: 1. Замість використання $ ARGV [0] використовуйте <> як введення. Він буде приймати дані від stdin, якщо немає аргументів як файли. 2. Для таких схем підрахунку непарних змін використовуйте регулярні вирази. Замість того, щоб робити непарні математичні операції, ви можете замінити цифри на число так, ніби це рядок. Найкраще, що ви можете одночасно використовувати на ньому математичні операції (як приріст), за умови, що це рядок, що складається повністю з цифр. Перевірте документацію для операторів регулярних виразів, оскільки вони можуть бути дуже корисними у багатьох випадках.
frederick

Вибачте, я натиснув Enter, і це збереглось, перш ніж закінчити коментар.
frederick

@frederick не будь таким скромним. Ми знаємо, що сталося!
Роберт Грант

1

Математика, 65

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

f = (n = #;
     l = 0; 
     While[n > 0,
      m = Floor[Log2[1 + n]];
      l += 10^(m - 1);
      n -= 2^m - 1
     ]; l)&

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

f[1000000000000000000]

Вихід:

11011110000010110110101100111010011101100100000000000001102

Починає видавати повідомлення про помилки MaxExtraPrecision десь минулого 10 ^ 228 (для чого він обчислює результат за 0,03 секунди на моїй машині)

Після видалення межі MaxExtraPrecision, вона буде обробляти числа до приблизно 10 ^ 8000 за секунду.

Вхід:

Timing[Block[{$MaxExtraPrecision = Infinity}, f[10^8000]];]

Вихід:

{1.060807, Null}

1

C, 95 байт

void f(unsigned long i,int*b){for(unsigned long a=~0,m=0;a;a/=2,b+=!!m)m|=*b=i/a,i-=a**b;*b=3;}

Це приймає ціле число і буфер, в який потрібно повернути цифри. Результати зберігаються в b, закінчуються значенням 3(яке не може відбутися у висновку). Нам не доводиться обробляти введення 0(оскільки в питанні вказано лише додатні цілі числа), тому немає спеціального кожуха, щоб уникнути порожнього виводу.

Розширений код

void f(unsigned long i,int*b)
{
    for (unsigned long a=~0, m=0;  a;  a/=2, b+=(m!=0)) {
        *b = i/a;               /* rounds down */
        i -= *b * a;
        m = m | *b;             /* m != 0 after leading zeros */
    }
    *b=3;                       /* add terminator */
}

Ми діємо шляхом послідовного віднімання, починаючи з найбільш значущої цифри. Єдине ускладнення полягає в тому, що ми використовуємо змінну, mщоб уникнути друку провідних нулів. Природне розширення unsigned long longможна зробити за бажанням ціною 10 байт.

Тестова програма

Передати номери для перетворення у вигляді аргументів команди. Він перетворює intбуфер масиву в рядок для друку. Час виконання становить менше однієї мілісекунди для введення 1000000000000000000.

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char**argv)
{
    while (*++argv) {
        unsigned long i = strtoul(*argv, NULL, 10);
        int result[1024];
        f(i,result);

        /* convert to string */
        char s[1024];
        {char*d=s;int*p=result;while(*p!=3)*d++=*p+++'0';*d=0;}
        printf("%lu = %s\n", i, s);
    }

    return EXIT_SUCCESS;
}

Результати тесту

$ ./51517 $(seq 20)
1 = 1
2 = 2
3 = 10
4 = 11
5 = 12
6 = 20
7 = 100
8 = 101
9 = 102
10 = 110
11 = 111
12 = 112
13 = 120
14 = 200
15 = 1000
16 = 1001
17 = 1002
18 = 1010
19 = 1011
20 = 1012

Я думаю, що версія C ++ схожа, але може використовуватись auto a=~0ullз невеликою перевагою ...
Toby Speight


0

CoffeeScript, 92 69 байт

На основі відповіді та оновлень Qwertiy :

f=(n)->s='1';(s=s.replace /(.?2|.$)/,(m)->[1,2,10][+m]||20)while--n;s

# older version, 92 bytes
f=(n)->s='1';(s=s.replace /(^2|02|12|20|.$)/,(m)->{0:1,1:2,2:10,12:20,20:100}[+m])while--n;s

2
Перетворення на іншу мову без простої оптимізації шляхом видалення непотрібних дужок у регулярному
виразі

@Qwertiy Я надав атрибуцію вашої відповіді, і з обома відповідями я не можу дати однакові результати без дужок у регулярному
виразі

Вся заміна замінюється. Для чого вам потрібно, щоб він був всередині групи? Версія JS працює у Firefox без дужок.
Qwertiy

0

Japt , 31 байт

_r/?2|.$/g_÷C ç20 ª°Zs3}}gU['0]

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

Майже прямий порт цього рішення JS . Не маю уявлення, чи є кращий спосіб.

Розпаковано та як це працює

X{Xr/?2|.$/gZ{Z÷C ç20 ||++Zs3}}gU['0]

X{     Declare a function...
Xr       Accept a string, replace the regex...
/?2|.$/g   /.?2|.$/   (g is needed to match *only once*, opposite of JS)
Z{       ...with the function... (matched string will be 0,1,2,02 or 12)
Z÷C        Implicitly cast the matched string into number, divide by 12
ç20        Repeat "20" that many times (discard fractions)
||         If the above results in "", use the next one instead
++Z        Increment the value
s3         Convert to base-3 string (so 0,1,2 becomes 1,2,10)
}}
gU['0] Repeatedly apply the function on "0", U (input) times

0

Стакс , 16 байт

üxëàè£öΦGΩ│Je5█ò

Запустіть і налагоджуйте його

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

Розпакований, неозорений та прокоментований, це виглядає приблизно так. У цій програмі реєстр x спочатку містить введення.

z       push []
{       start block for while loop
 |X:2N  -log2(++x)
 {^}&   increment array at index (pad with 0s if necessary)
 xc:G-X unset high bit of x; write back to x register
w       while; loop until x is falsy (0)
$       convert to string

Виконати цей

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