Numerazione delle pagine in stile xkcd


65

Il libro di Randall Munroe "xkcd, volume 0" utilizza un sistema di numeri piuttosto strano per i numeri di pagina. I primi numeri di pagina sono

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

Questo sembra un po 'come ternaria, a meno di notare che salta da 20dritta a 100, da 120a 200e da 200a 1000. Un modo per definire questa sequenza è dire che enumera tutti i numeri ternari che contengono al massimo uno 2e non 1dopo 2. Puoi trovarlo su OEIS nella voce A169683 . Questo sistema numerico è noto come binario obliquo .

Il tuo compito è trovare la rappresentazione di un dato numero intero positivo Nin questo sistema di numeri.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN (o l'alternativa più vicina), l'argomento della riga di comando o l'argomento della funzione e producendo il risultato tramite STDOUT (o l'alternativa più vicina), il valore di ritorno della funzione o il parametro della funzione (out).

L'output può essere una stringa, un numero con una rappresentazione decimale uguale alla rappresentazione binaria inclinata o un elenco di cifre (come numeri interi o caratteri / stringhe). Non è necessario restituire zero iniziali.

Questo è il golf del codice, quindi vince la risposta più breve (in byte).

Curiosità: in realtà questo sistema numerico ha qualche merito. Quando si incrementa un numero, cambierete sempre al massimo due cifre adiacenti - non dovrete mai portare la modifica attraverso l'intero numero. Con la giusta rappresentazione che consente l'incremento in O (1).

Casi test

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

Darò una ricompensa alla risposta più breve in grado di risolvere l'ultimo caso di test (e qualsiasi altro input di grandezza simile, quindi non pensare di codificarlo in modo rigido) in meno di un secondo.

Classifiche

Ecco uno snippet di stack per generare sia una classifica regolare che una panoramica dei vincitori per lingua.

Per assicurarti che la tua risposta venga visualizzata, ti preghiamo di iniziare la risposta con un titolo, usando il seguente modello Markdown:

# Language Name, N bytes

dov'è Nla dimensione del tuo invio. Se si migliora il punteggio, è possibile mantenere i vecchi punteggi nel titolo, colpendoli. Per esempio:

# 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
Ho avuto quel libro da quando è uscito per la prima volta e non ho mai notato la numerazione delle pagine.
Alex A.

2
@AlexA. Ce l'ho sul mio Kindle dove non puoi fare nessuna numerazione delle pagine interessante.
LegionMammal978,

21
@ LegionMammal978: Tragic.
Alex A.

1
@ SuperJedi224 Il consenso sembra essere no , quindi mi dispiace (farei un'eccezione dal consenso se fosse l'unico tipo di input che la tua lingua potrebbe gestire, ma non sembra essere il caso).
Martin Ender,

4
Questo mi ricorda come contavo quando avevo 3 anni. Pensai: "non ce ne sono cinquantanove, quindi dopo centonove devono essere duecento". Mi sono reso conto del mio errore solo vedendo la differenza tra 59->60e 109->110, con lo 0 extra.
Cyoce

Risposte:


12

Pyth, 17 byte

Ljb3ye.f!-P-yZ01Q

Questo è un po 'ridicolmente lento - O(output^log_2(3)). È esponenziale nella lunghezza dell'input, ma non doppiamente esponenziale, come alcune delle risposte sulla pagina. Alcune idee tratte dalla risposta di @ Dennis, qui .

Dimostrazione.

Fa uso della funzione .f"loop fino a quando non sono state trovate n corrispondenze" di Pyth.


32

CJam, 24 23 22 21 19 byte

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

Questo è un approccio O (log n) , in cui n è l'input, che completa immediatamente l'ultimo caso di test. Converte n direttamente in binario obliquo, usando la divisione modulare per i valori della cifra 1 .

Questo codice termina con un errore che va a STDERR con l'interprete Java, che è consentito in base al consenso su Meta .

Se provi questo codice nell'interprete CJam , ignora tutto tranne l'ultima riga di output.

L'errore può essere eliminato, al costo di 2 byte, anteponendo 2>a W%.

Grazie a @ MartinBüttner per giocare a golf con un byte.

sfondo

La rappresentazione binaria di inclinazione a k ... a 0 corrisponde all'intero n = (2 k + 1 -1) a k + ... + (2 1 -1) a 0 .

Poiché entrambi (2 k -1) + ... + (2 1 -1) = 2 k + 1 - (k + 2) e (2 k -1) + ... + 2 (2 j -1) = 2 k + 1 - (2 j + 1 - 2 j + k + 1) sono meno di 2 k + 1 -1 , i valori di un k ad un 0 può essere recuperato per divisione modulare successive da 2 k + 1 -1 , 2 k -1 , ecc.

Per cominciare, dobbiamo prima trovare il valore di 2 k + 1 -1 . Poiché n è al massimo 2 (2 k + 1 -1) , l'intero n + 1 deve essere strettamente inferiore a 2 k + 2 .

Quindi, prendendo la parte intera del logaritmo binario di n + 1 si ottiene k + 1 .

Infine, osserviamo che l'intero n + 1 ha ⌊log 2 (n + 1) ⌋ cifre nella base 2.

Come funziona

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#

Nelle ultime due iterazioni, eseguiamo la divisione modulare per 1 e 0 . Il primo spinge uno 0 indesiderato nello stack. L'ultimo tentativo di esecuzione 0 0 md, che estrae entrambi 0 s indesiderati dallo stack, esce immediatamente invece di spingere qualsiasi cosa e scarica lo stack su STDOUT.


28

Python 2, 67 byte

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

Sembra funzionare per i casi di test indicati. Se ho O(place values set in output)capito bene, dovrebbe trattarsi di questo , quindi fa facilmente l'ultimo caso.

Chiama come f(100). Restituisce una rappresentazione decimale uguale al binario di inclinazione.

Python 3, 65 byte

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

Leggermente meno efficiente ma comunque logaritmico, quindi l'ultimo caso è quasi istantaneo.

Chiama come g(100). Restituisce un elenco di cifre.


si 2andcompila in 3? Sono in 2 e 2and2genera un errore di sintassi
TankorSmash,

3
@TankorSmash 2and2non funzionerebbe perché verrebbe analizzato come 2 and2- try 2and 2, che dovrebbe funzionare se la tua versione di Python è abbastanza nuova (testata in Python 2.7.10)
Sp3000

Oh bello, hai ragione. Anche su 2.7.3 funziona.
TankorSmash,

12

CJam, 22 21 20 byte

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

Questo è un approccio O (e n n) , dove n è l'input. Elenca i primi ⌊e n numeri interi non negativi nella base 3, elimina quelli che hanno 2 se 1 s dopo i primi 2 (se presenti) e seleziona n + 1 ° .

Provalo online nell'interprete CJam .

Come funziona

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 byte

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

Funziona in O (log (input ())), ben meno di un secondo per il caso di test finale. Basato su una corsa fino al loop degli errori. Nessuna nuova riga finale.

Dimostrazione.

Spiegazione:

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 viene inizializzato sul valore della posizione della cifra binaria di inclinazione più piccola che è maggiore dell'input. Quindi, ogni volta attraverso il ciclo, facciamo quanto segue:

  • Rimuovere ogni cifra di valore Jda Qcon =%QJ. Ad esempio, se Q=10e J=7, Qdiventa 3, che corrisponde al mutare binario skew da 110a 10. Questo non ha alcun effetto nella prima iterazione.
  • Passare Jal valore binario di inclinazione più piccolo successivo con =/J2. Questa divisione viene divisa per 2, cambiando J=7ad J=3esempio. Poiché ciò accade prima che venga emessa la prima cifra, Jviene inizializzata una posizione della cifra più alta del necessario.
  • Trova il valore attuale della cifra con /QJ(efficacemente).
  • Stampa quel valore con p, anziché con la stampa predefinita di Pyth, per evitare la nuova riga finale.

Questo ciclo si ripeterà fino a Jdiventare zero, a quel punto verrà generato un errore di divisione per zero e il ciclo terminerà.


8

ES6, 105 byte

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)

L'utilizzo è: f(1048576)=> `" 10000000000000000001 "

Prova l'ultimo argomento a tuo rischio e pericolo. Mi sono arreso dopo 5 secondi.

E bella stampa con commenti!

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
A proposito, le funzioni senza nome sono perfettamente accettabili, quindi non è necessario f=.
Martin Ender,

2
-16 byte: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 l'

@nderscore Abbastanza bello: D
Bussola,

1
-7 byte se si utilizza ES7: sostituirlo Math.pow(3,s.length+c)con 3**(s.length+c).
Gustavo Rodrigues,

3
@GustavoRodrigues Non ho nemmeno finito di imparare ES6! @ _ @
Compass

7

Retina, 55 byte

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

Riceve input in unario.

Ogni riga dovrebbe andare al proprio file ma è possibile eseguire il codice come un file con il -sflag. Per esempio:

> echo 11111|retina -s skew
12

Metodo: esegue l'incremento su un numero di input della stringa volte a partire dalla stringa 0.

Utilizziamo le seguenti regole di incremento:

  • se contiene 2: ^2 -> ^12; 02 -> 12;12 -> 20
  • se non contiene 2: 0$ -> 1$;1$ -> 2$

(Ce ne può essere al massimo uno 2nella stringa; ^e $segna l'inizio e la fine della stringa nelle regole.)

Ulteriori informazioni su Retina.


7

Java, 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;}

Questa risposta assume la forma di una singola funzione anonima che accetta un argomento intero e restituisce la risposta come stringa. Di seguito è una classe completa per testare questa soluzione.

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}

Questo è un bruto-forcer, quindi è piuttosto lento per numeri più grandi.

Produzione:

$ ./xkcdnum.sh 1000
111110120
$ 

5

Java, 337 335 253 246 244 byte

Un metodo che accetta l'indice come a longe restituisce il risultato come stringa

Utilizza un longindice per poter teoricamente gestire l'ultimo caso di test, ma non lo suggerirei davvero .

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
Potresti accorciarlo un po 'rendendolo una funzione anziché un programma completo (e prendendo l'input come argomento anziché da uno scanner).
Geobits,

2
Non sono necessarie le parentesi graffe if(j == 0) nell'istruzione (quattro byte). Non è necessario dichiarare k; puoi semplicemente usarlo di jnuovo (altri quattro). È possibile utilizzare l'inferenza di tipo generico (in Java 7) nella dichiarazione dell'elenco ( new ArrayList<>();) (un altro 4)
durron597

4

Haskell, 73 72

Grazie a @nimi per 1 byte!

Questa soluzione non vincerà alcuna ricompensa, gli ultimi test di coppia richiedono una quantità eccessiva di tempo per essere eseguiti, ma, penso di averlo giocato abbastanza bene.

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]!!)

Questa soluzione è un approccio piuttosto ingenuo che calcola il numero binario di inclinazione nincrementando 0 nvolte.


4

CJam, 24 byte

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

Questo è un approccio O (n log n) , dove n è l'input. Inizia con la rappresentazione binaria inclinata di 0 e incrementa il numero intero corrispondente n volte.

Provalo online nell'interprete CJam .

sfondo

L'incremento di un numero in binario obliquo può essere eseguito seguendo due semplici passaggi:

  1. Sostituisci un eventuale 2 con uno 0 .

  2. Se un 2 è stato sostituito, incrementa la cifra alla sua sinistra.

    Altrimenti, incrementa l'ultima cifra.

Come funziona

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 byte

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

La mia matematica è inefficiente e il mio golf potrebbe usare il lavoro. Ma è il mio primo tentativo di PoG e ho pensato di provarlo. Una specie di modo Brute Force però.

Conta solo per 1 a meno che l'ultima cifra sia un 2, quindi fa un passo indietro di 2 e salta in avanti di 10. Più gli 0 finali.

Questo smette di funzionare a 65534 perché VBA insiste nel dare output in notazione scientifica, ma la logica dovrebbe funzionare bene per numeri ancora più alti

In attesa di suggerimenti sul golf, VBA non è molto adatto al golf ma non è spesso rappresentato, e penso che possa battere Java per molto.

Edit1: Grazie Manu per aver contribuito a radere 62 byte

Edit2: scambiato debug.printper msgboxcome output. 5 byte salvati


1
È possibile rimuovere le parentesi da Debug.Print (q). Inoltre, puoi rimuovere la maggior parte degli spazi bianchi (l'editor li riporterà, ma non sono necessari). Non è necessario dichiarare k as Long, basta scrivere k. Sarà una variabile del tipo Variant e il codice continuerà a funzionare. Con questi suggerimenti dovresti scendere a ~ 165 byte.
CommonGuy

Qualche altro pensiero: puoi tralasciare il primo e l'ultimo argomento di InStr, sono facoltativi. Trim()non è necessario, poiché non hai spazi bianchi. Applicato correttamente, ottengo 147 byte .
CommonGuy

1
Grazie per l'aiuto Manu, Una domanda veloce, l'output dovrebbe essere l'output standard. Non sono sicuro di cosa sarebbe in VBA. debug.print qsarebbe l'output standard? msgbox qè più corto, ma sembra che non sia proprio l'output standard. Sheet1.cells(1,1)sembra l' output tipico ma assume che funzioni in Excel. Non sono sicuro di quanto sia rigoroso il code-golf riguardo a questo tipo di cose.
JimmyJazzx,

Complimenti, hai battuto la risposta di Java;) Neanche io lo so ... Usa solo MsgBox, se qualcuno si lamenta, puoi ancora cambiarlo.
CommonGuy

4

Javascript ES6, 99 86 78 76 72 caratteri

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}

Test:

;[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"

Curiosità: in realtà questo sistema numerico ha qualche merito. Quando si incrementa un numero, cambierete sempre al massimo due cifre adiacenti - non dovrete mai portare la modifica attraverso l'intero numero. Con la giusta rappresentazione che consente l'incremento in O (1).

Grazie per il fatto - è la base della mia soluzione :)


Come potrei lasciare parentesi inutili nella regex? o_O
Qwertiy,

3

Ottava, 107 101 byte

Dovrebbe essere O (log n) se sto immaginando questo giusto ...

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

Pretty-print:

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

Ero un po 'stremato nell'affrontare la sfida finale, poiché Octave di default tratta tutto come numeri a virgola mobile e non avevo la precisione necessaria per calcolare l'ultimo. L'ho aggirato spendendo byte preziosi per forzare tutto ad essere un numero intero senza segno. Il risultato dell'ultimo era troppo grande per essere trattato come un numero, quindi il risultato è una stringa.

Output (sto includendo 1e18 - 1per mostrare che posso farlo con precisione, e l'ultimo set di output mostra quanto tempo ci vuole per calcolare quel valore):

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 byte

EDIT: le versioni originali di questo codice produrranno un output errato per alcuni numeri, questo è stato corretto.

Con ogni query qui, basta aggiungere il numero da calcolare prima della prima virgola.

Tutti sanno che T-SQL è il miglior linguaggio per giocare a golf. Ecco una versione che calcolerà anche l'ultimo caso di test. Sulla macchina su cui l'ho provato, ha funzionato in meno di un secondo, sarei interessato a vedere come funziona per tutti gli altri.

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

Ed eccolo di nuovo, ma leggibile:

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

Se uso solo ints, questo può essere un po 'più breve, uscendo a 157 byte:

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

E ancora una volta, più leggibile:

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

Ricorda che @è un identificatore valido in sql e molto probabilmente puoi cavartela Char(8000) che è ancora più economica di nvarchar (max). Puoi anche convertire in charinvece di varchar, o usare la strfunzione.
Michael B,

@MichaelB Oh, pensavo di aver usato @, sciocco me. Il CHAR(8000)consiglio è abbastanza buono, ci proverò. Mi sembra sempre di dimenticare l'esistenza di STR()ringraziamenti per il testa a testa.
PenutReaper,

in realtà non aiuta. Tuttavia, è possibile riscrivere la parte dopo il CTE in :: select @t=concat(@t,@/i)che dovrebbe essere più piccola. Richiede sql2012 però.
Michael B,

@MichaelB ah. CONCAT, Sono del 2008. Quindi non posso provarlo senza usare un violino SQL in questo momento. Buona chiamata però.
PenutReaper

3

Codice di Turing Machine, 333 293 byte

Sto usando una codifica come usata qui .

Questa macchina utilizza 9 stati e 11 colori.

Se è consentito l'input binario, questo può essere ridotto a soli 4 colori, risparmiando alcune decine di byte nel processo.

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

Se il link sopra non funziona (a volte funziona per me, altre volte la pagina si rifiuta di caricare) puoi anche testarlo usando questa implementazione java.


2

Perl, 66 byte

Il numero deve essere inserito tramite STDIN.

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

Potresti spiegare come funziona la tua soluzione? Non vedo come è necessario (.?)in $2fin (.*)nel $1dovrebbe essere avido e ottenere che il carattere prima. Ma se viene rimosso il codice non produce più i risultati corretti! A proposito, non hai bisogno del finale ;.
CJ Dennis,

@CJDennis Grazie per il byte salvato. Comunque, il.? otterrà la cifra che precede i due a meno che non vi sia alcuna cifra lì (es. 20). In casi come 120 o 10020, i gruppi regex come questo: () (1) 2 (0) e (10) (0) 2 (0). Quindi il primo gruppo viene semplicemente ignorato, il secondo gruppo (che è sempre una cifra se possibile o vuoto) viene incrementato e il terzo gruppo (sempre costituito da zero) viene ignorato e viene aggiunto uno zero. Ho semplicemente usato la voce OEIS come mia guida per questa regex.
Federico,

Ho ricevuto il tuo codice fino a 53 byte: $c=<>;s/(.*)2(.*)/$1+1 .$2.0/e||$_++while($c--);print. Avevo ragione, (.?)non ho mai catturato nulla.
CJ Dennis,

Può essere ottimizzato per $_=1;$c=<>;s/(.?)2/1+$1.0/e||$_++while(--$c);print, che è di 50 byte. .*all'inizio o alla fine può essere ottimizzato, se lo si sostituisce semplicemente con il testo originale. Inoltre non c'è motivo di aggiungere lo 0 alla fine, poiché nell'originale sono sempre presenti solo zeri $3.
Thraidh,

2

Pyth, 19 byte

m/=%Qtydtd^L2_SslhQ

Complessità logaritmica. Termina facilmente nel tempo necessario. Uscita sotto forma di un elenco di cifre.

Dimostrazione .


2

Perl, 84 70 67 byte

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

Non molto golfy, sta migliorando ma funziona molto velocemente!

Il suggerimento di Dennis arriva a 51 (50 byte + -p switch)

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

Essa deve essere chiamato come perl -p skew_binary.pl num_list.txtse num_list.txtcontiene una singola linea con il numero di codificare su di esso.


@frederick siamo ai margini dei nostri posti in attesa di 2.
Robert Grant,

@RobertGrant Ha scritto il suo commento da due cose a una cosa!
CJ Dennis,

Due cose: 1. Invece di usare $ ARGV [0], usa <> come input. Ci vorrà input da stdin a meno che non ci siano file come argomenti. 2. Per schemi di conteggio dispari come questo, utilizzare espressioni regolari. Invece di eseguire operazioni matematiche dispari, è possibile sostituire le cifre in un numero come se fosse una stringa. La parte migliore è che puoi usare contemporaneamente le operazioni matematiche (come l'incremento), purché si tratti di una stringa composta interamente da cifre. Controlla la documentazione per gli operatori delle espressioni regolari, poiché possono essere molto utili in così tante occasioni.
Federico,

Spiacente, ho premuto invio ed è stato salvato prima di aver terminato il commento.
Federico,

@frederick non essere così modesto. Sappiamo cosa è successo!
Robert Grant,

1

Mathematica, 65 anni

Dovrebbe essere abbastanza veloce, anche se devo ammettere di aver dato una sbirciatina alle altre osservazioni prima di farlo.

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

Uso:

f[1000000000000000000]

Produzione:

11011110000010110110101100111010011101100100000000000001102

Inizia a inviare messaggi di errore MaxExtraPrecision da qualche parte oltre 10 ^ 228 (per i quali calcola il risultato in 0,03 secondi sulla mia macchina)

Dopo aver rimosso il limite MaxExtraPrecision, gestirà numeri fino a circa 10 ^ 8000 al secondo.

Ingresso:

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

Produzione:

{1.060807, Null}

1

C, 95 byte

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

Questo accetta un numero intero e un buffer in cui restituire le cifre. I risultati vengono archiviati b, terminati con valore 3(che non può verificarsi nell'output). Non è necessario gestire l'input di 0(poiché la domanda specificava solo numeri interi positivi), quindi non è presente un case speciale per evitare output vuoti.

Codice espanso

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 */
}

Operiamo per sottrazione successiva, iniziando dalla cifra più significativa. L'unica complicazione è che usiamo la variabile mper evitare la stampa di zeri iniziali. unsigned long longSe lo si desidera, è possibile effettuare un'estensione naturale al costo di 10 byte.

Programma di test

Passa i numeri da convertire come argomenti di comando. Converte il intbuffer di array in una stringa di cifre stampabile. Il tempo di esecuzione è inferiore a un millisecondo per l'input 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;
}

Risultati del test

$ ./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

Immagino che una versione C ++ sia simile, ma può essere usata auto a=~0ullper un leggero vantaggio ...
Toby Speight,


0

CoffeeScript, 92 69 byte

Basato sulla risposta e sugli aggiornamenti di 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
La conversione in un'altra lingua senza nemmeno una semplice ottimizzazione rimuovendo le parentesi non necessarie nella regex non mi sembra interessante ...
Qwertiy,

@Qwertiy Ho fornito l'attribuzione alla tua risposta e con entrambe le risposte non riesco a produrre gli stessi risultati senza le parentesi nel regex
rink.attendant.6

L'intera ricorrenza viene sostituita. Perché ne hai bisogno per far parte del gruppo? La versione JS funziona in Firefox senza parentesi.
Qwertiy,

0

Japt , 31 byte

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

Provalo online!

Porta quasi diretta di questa soluzione JS . Non ho idea se c'è un modo migliore.

Disimballato e come funziona

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

Stax , 16 byte

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

Esegui ed esegui il debug

Non sono sicuro di quale sia esattamente la classe di complessità formale, ma è abbastanza veloce per eseguire tutti i casi di test in un decimo di secondo su questa macchina.

Disimballato, non golfato e commentato, sembra così. In questo programma, il registro x contiene originariamente l'input.

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

Esegui questo

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.