xkcd-Style Sayfa Numaralandırma


65

Randall Munroe'nın kitabı "xkcd, hacim 0", sayfa numaraları için oldukça tuhaf bir sayı sistemi kullanır. İlk birkaç sayfa numarası

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

Bu üçlü gibi biraz görünüyor, ama gelen atlar olduğunu fark 20düz için 100gelen 120için 200ve gelen 200etmek 1000. Bu diziyi tanımlamanın bir yolu, en fazla bir tane içeren 2ve 1ondan sonra olmayan tüm üçlü sayıları saydığını söylemektir 2. Bunu A169683 numaralı girişte OEIS'te bulabilirsiniz . Bu sayı sistemi çarpık ikili olarak bilinir .

Göreviniz N, bu sayı sisteminde verilen bir pozitif tamsayı gösterimini bulmaktır .

STDIN (veya en yakın alternatif), komut satırı argümanı veya işlev argümanı yoluyla giriş alarak ve sonucu STDOUT (veya en yakın alternatif), fonksiyon dönüş değeri veya function (out) parametresi ile çıktı alarak bir program veya işlev yazabilirsiniz.

Çıktı, bir dize, çarpık ikili gösterime eşit bir ondalık gösterime sahip bir sayı veya bir sayılar listesi (tamsayılar veya karakterler / dizeler olarak) olabilir. Baştaki sıfırları geri döndürmemelisiniz.

Bu kod golf, yani en kısa cevap (bayt cinsinden) kazanır.

Eğlenceli gerçek: Bu sayı sistemine aslında bir miktar hak var. Bir sayıyı artırırken, her zaman en çok iki bitişik haneyi değiştirirsiniz - değişikliği hiçbir zaman tüm sayı boyunca taşımak zorunda kalmazsınız. O (1) 'de artışa izin veren doğru gösterimle.

Test Kılıfları

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

Son test vakasını (ve benzer büyüklükteki diğer girdilerin hepsini çözebilecek en kısa cevaba) bir saniyeden daha kısa sürede çözeceğim.

Liderler

Burada hem düzenli bir lider tablosu hem de kazananların dile göre bir genel bakışını oluşturmak için bir Stack Snippet'i var.

Cevabınızın göründüğünden emin olmak için, lütfen aşağıdaki Markdown şablonunu kullanarak cevabınızı bir başlık ile başlatın:

# Language Name, N bytes

Gönderinizin Nbüyüklüğü nerede ? Puanınızı yükseltirseniz, başlıkları üstüne vurarak eski skorları başlıkta tutabilirsiniz. Örneğin:

# 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
Bu kitabı ilk çıktığımdan beri kullandım ve sayfa numaralandırmasını hiç fark etmedim.
Alex A.

2
@AlexA. Kindle'ımda var, burada ilginç sayfa numaralandırması yapamazsınız.
LegionMammal978 11:15

21
@ LegionMammal978: Trajik.
Alex A.

1
@ SuperJedi224 Konsensüs hayır gibi görünüyor , çok üzgünüm (eğer dilinizin üstesinden gelebilecek tek tür girdi olsaydı, fikir birliği dışında bir istisna yapardım, ancak durum böyle görünmüyordu).
Martin Ender,

4
Bu bana 3 yaşımdayken nasıl saydığımı hatırlatıyor. Neden: "elli on yok, o yüzden yüz dokuzdan sonra iki yüz olmalı" dedi. Ben sadece arasındaki farkı görünce benim hata fark 59->60ve 109->110ekstra 0. ile
Cyoce

Yanıtlar:


12

Pyth, 17 bayt

Ljb3ye.f!-P-yZ01Q

Bu biraz gülünç yavaş O(output^log_2(3)). Girişin uzunluğunda üstel, ancak sayfadaki bazı cevaplar gibi iki kat üstel değil. @ Dennis'in cevabından bazı fikirler geldi .

Gösteri.

Bu yararlanır .ffonksiyonunu "n maçları bulunmuştur kadar döngü" Pyth en.


32

CJam, 24 23 22 21 19 bayt

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

Bu, bir N (log n) yaklaşımıdır, burada n , girdidir ve son test vakasını anında tamamlar. 1 rakamının değerlerine göre modüler bölme kullanarak n'yi doğrudan çarpık ikiliye dönüştürür .

Bu kod, STDERR’e Java tercümanı ile gider ve Meta’daki uzlaşmaya göre izin verilir .

Bu kodu CJam yorumlayıcısında denerseniz , sadece son çıktı satırı dışında her şeyi yoksayın.

Hata prepending ile, 2 bayt pahasına, elimine edilebilir 2>için W%.

Bir byte'ı attığı için @ MartinBüttner'e teşekkürler.

Arka fon

Çarpık ikili gösterimi a k ... a 0 , n = (2 k + 1 -1) a k + ... + (2 1 -1) a 0 tamsayısına karşılık gelir .

Her ikisi de (2 k -1) + ... + (2 1 -1) = 2 k + 1 - (k + 2) ve (2 k -1) + ... + 2 (2 j -1) = 2 k + 1 - (2 j + 1 - 2 j + k + 1) olan en az 2 1 + k -1 , değerleri , bir k için bir 0 ile arka arkaya modüler bölme ile elde edilebilir 2 k + 1 -1 , 2 k -1 , vb.

Başlamak için önce 2 k + 1 -1 değerini bulmalıyız . Bu yana , n en olan 2 (2 k + 1 1) , tam sayı , n + 1 kesin daha küçük olmalıdır 2 k + 2 .

Böylece, n + 1'in ikili logaritmasının tamsayı kısmını almak k + 1 verir .

Son olarak, n + 1 tamsayısının , taban 2'de ⌊log 2 (n + 1) ⌋ rakamları olduğunu gözlemledik .

Nasıl çalışır

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#

Son iki yinelemede, modüler bölünmeyi 1 ve 0 oranında yaparız . İlki yığında istenmeyen bir 0 iter . 0 0 mdİstenmeyen 0 saniyeyi yığından çıkan son çalıştırma girişimi , herhangi bir şeyi itmek yerine hemen çıkar ve yığını STDOUT'a bırakır.


28

Python 2,67 bayt

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

Verilen test durumları için çalışmak gibi görünüyor. Eğer bu hakkım varsa, bunun olması gerekiyor O(place values set in output), bu yüzden son davayı kolaylıkla yapıyor.

Gibi ara f(100). Çarpık ikiliye eşit bir ondalık gösterimi döndürür.

Python 3, 65 bayt

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

Biraz daha az verimli ama yine de logaritmik, bu yüzden son vaka neredeyse anında.

Gibi ara g(100). Rakamların listesini döndürür.


yok 2and3'te derlemek? 2 yaşıyorum ve 2and2bir sözdizimi hatası atıyor
TankorSmash

3
@TankorSmash 2and2işe yaramaz çünkü Python sürümünüz yeterince yeni ise çalışmalı 2 and2- denemeye 2and 2çalışılır (Python 2.7.10'da test edilmiştir)
Sp3000

Güzel, haklısın. 2.7.3'te bile çalışıyor.
TankorSmash

12

CJam, 22 21 20 bayt

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

Bu bir O (e n n) yaklaşımıdır, burada n girdidir. İlk listeler ⌊e n , tabanın 3 negatif olmayan tam sayı sahip olanlar elimine 2 s veya 1 ilk sonra s , 2 (eğer varsa) ve seçen n + 1 inci .

CJam tercümanında çevrimiçi olarak deneyin .

Nasıl çalışır

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 bayt

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

Son test durumu için bir saniyenin altında, O (log (input ())) içinde çalışır. Hata döngüsüne kadar bir koşu etrafında. Sondaki yeni satır yok.

Gösteri.

Açıklama:

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, girişten daha büyük olan en küçük eğriltme ikili basamak değerinin değeri ile başlatıldı. Sonra, her döngüde aşağıdakileri yaparız:

  • Değerin her hanesini kaldırın Jgelen Qile =%QJ. Örneğin, Q=10ve J=7, Qolur 3, Asimetri ikili değiştirme karşılık gelen 110için 10. Bunun ilk tekrarlamada etkisi yoktur.
  • Değişim Jile sonraki daha küçük çarpık ikili taban değerine =/J2. Bu değiştirme, 2 ile bölünmesi çekilir J=7için J=3, örneğin. Bu ilk rakam çıkmadan önce gerçekleştiğinden, Jgerektiğinden daha yüksek bir basamak pozisyonda intialize edilir.
  • /QJ(Rakamlarla) gerçek rakam değerini bulun .
  • pSondaki yeni satırı önlemek için Pyth `un varsayılan baskısı yerine bu değeri yazdırın .

Bu döngü Jsıfıra gelinceye kadar tekrar eder , bu noktada sıfır hatayla bölme atılır ve döngü sona erer.


8

ES6, 105 bayt

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)

Kullanımı: f(1048576)=> `" 1000000000000000000001 "

Son argümanı kendi tehlikende test et. 5 saniye sonra pes ettim.

Ve yorumlarınızla güzel baskı!

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, adlandırılmamış işlevler tamamen kabul edilebilir, bu yüzden gerek yok f=.
Martin Ender

2
-16 bayt: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 11:15

@nderscore Çok havalı: D
Compass

1
-7 bayt Eğer ES7 kullanırsanız: değiştirin Math.pow(3,s.length+c)ile 3**(s.length+c).
Gustavo Rodrigues

3
@GustavoRodrigues ES6 öğrenmeyi bile bitirmedim! @ _ @
Compass

7

Retina, 55 bayt

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

Aynı zamanda girdi alır.

Her satır kendi dosyasına gitmelidir, ancak kodu -sbayrakla bir dosya olarak çalıştırabilirsiniz . Örneğin:

> echo 11111|retina -s skew
12

Yöntem: Dizeden başlayarak dizgenin giriş sayısı üzerinde artış yapar 0.

Aşağıdaki artış kurallarını kullanıyoruz:

  • içeriyorsa 2: ^2 -> ^12; 02 -> 12;12 -> 20
  • içermiyorsa 2: 0$ -> 1$;1$ -> 2$

(Orada en fazla biri olabilir 2dizede; ^ve $kuralları dize başlangıcını ve sonunu belirler.)

Retina hakkında daha fazla bilgi.


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

Bu cevap, bir tamsayı argümanı alan ve cevabı bir Dize olarak döndüren tek bir isimsiz fonksiyon biçimini alır. Aşağıda bu çözümü test etmek için tam bir sınıf var.

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}

Bu bir kabadayıdır, bu yüzden daha büyük sayılar için oldukça yavaş.

Çıktı:

$ ./xkcdnum.sh 1000
111110120
$ 

5

Java, 337 335 253 246 244 bayt

Dizinde a olarak alan longve sonucu dizge olarak döndüren bir yöntem

longİndeks için bir kullanır , böylece son test senaryosunu teorik olarak ele alabilir , ancak bunu gerçekten önermem.

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
Tam bir program yerine bir işlev haline getirerek (ve bir Tarayıcı yerine bir argüman olarak girdi alarak), bunu biraz kısaltabilirsiniz.
Geobits,

2
İfadedeki parantezlere ihtiyacınız yoktur if(j == 0) (dört bayt). İlan etmek gerekmez k; Sadece jtekrar kullanabilirsiniz (dört tane daha). Liste bildiriminizde ( new ArrayList<>();) (başka bir 4) genel türdeki çıkarımı (Java 7'de) kullanabilirsiniz
durron597

4

Haskell, 73 72

1 byte için @nimi'ye teşekkürler!

Bu çözüm herhangi bir ödül kazanmayacak, son çift testlerinin çalıştırılması çok zaman alıyor ancak sanırım oldukça iyi golf oynadım.

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

Bu çözüm, çarpık ikilik sayılarını n0 nkat artırarak hesaplayan oldukça naif bir yaklaşımdır .


4

CJam, 24 bayt

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

Bu bir O (n log n) yaklaşımıdır, burada n girişdir. 0'ın çarpık ikili gösterimi ile başlar ve karşılık gelen tamsayı n sürelerini arttırır.

CJam tercümanında çevrimiçi olarak deneyin .

Arka fon

İkili basamaktaki bir sayıyı artırmak, iki kolay adımı izleyerek yapılabilir:

  1. Nihai bir yerine 2 bir yan 0 .

  2. Bir halinde 2 değiştirildiği, sol sayıyı arttırır.

    Aksi takdirde, son rakamı artırın.

Nasıl çalışır

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 bayt

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

Matematiğim verimsiz ve golf oynamak iş kullanabilir. Ama bu benim PoG'a ilk girişim ve bunu denemeyi düşündüm. Bir Brute Force yolu olsa da.

Son rakam 2 değilse sadece 1 ile sayıyor, sonra 2 ile geri adım atıyor ve 10 atlıyor.

Bu, 65534'te çalışmayı durdurur, çünkü VBA bilimsel gösterime çıktı vermek için ısrar eder, ancak mantık daha yüksek sayılar için iyi çalışmalıdır.

Golf önerileri için sabırsızlanıyorum, VBA çok golf dostu değil, ancak çoğu kez temsil edilmiyor ve Java'nın uzunluğunu yenebileceğini düşünüyorum.

Düzenleme1: 62 baytın tıraş edilmesine yardımcı olduğu için teşekkürler Manu

Edit2: takas debug.printiçin msgboxçıktı olarak. 5 bayt kaydedildi


1
Parantezleri kaldırabilirsiniz Debug.Print (q). Ayrıca, boşlukların çoğunu kaldırabilirsiniz (editör onları geri koyar, ancak gerekli değildir). Beyan etmeye gerek yok k as Long, sadece yazın k. Variant türünde bir değişken olacak ve kod hala çalışacak. Bu ipuçlarıyla ~ 165 bayta kadar inmelisiniz.
CommonGuy

Bazı düşünceler: InStrİsteğe bağlı olan ilk ve son argümanı bırakabilirsiniz . Trim()gerekli değil, çünkü boş yeriniz yok. Doğru uygulandığında 147 byte'a ulaşıyorum .
CommonGuy

1
Yardım Manu için teşekkürler, Hızlı bir soru, Çıktı, Standart Çıktı olmalıdır. Bunun VBA’da ne olacağından emin değilim. debug.print qStandart çıktı olur mu? msgbox qdaha kısa ama yine de standart çıktı gibi görünmüyor. Normal çıktı Sheet1.cells(1,1)gibi görünüyor ancak excel ile çalıştığını varsayıyor. Kod golfün bu tür şeylerle ilgili ne kadar katı olduğundan emin değilim.
JimmyJazzx

Tebrikler, java cevabını yendiniz;) Ben de bilmiyorum ... Sadece MsgBoxbirini kullanın , birileri şikayet ederse yine de onu değiştirebilirsiniz.
CommonGuy

4

Javascript ES6, 99 86 78 76 72 karakter

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}

Ölçek:

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

Eğlenceli gerçek: Bu sayı sistemine aslında bir miktar hak var. Bir sayıyı artırırken, her zaman en çok iki bitişik haneyi değiştirirsiniz - değişikliği hiçbir zaman tüm sayı boyunca taşımak zorunda kalmazsınız. O (1) 'de artışa izin veren doğru gösterimle.

Gerçek için teşekkürler - bu benim çözümümün temelidir :)


Gereksiz diş tellerini regex içinde nasıl bırakabilirim? o_O
Qwertiy

3

Octave, 107 101 bayt

Bunu doğru anlıyorum eğer O (log n) olmalı ...

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

Son meydan okumayı çözerken biraz şaşırdım, çünkü Octave varsayılan olarak her şeyi kayan nokta sayıları olarak görür ve sonuncuyu hesaplamak için gerekli hassasiyete sahip değildim. Her şeyi imzasız bir tamsayı olmaya zorlamak için değerli baytlar harcayarak bunun üstesinden geldim. Sonuncunun sonucu sayı olarak değerlendirilemeyecek kadar büyüktü, bu yüzden sonuç bir dizgedir.

Çıktı (Bunu 1e18 - 1doğru şekilde yapabileceğimi göstermeyi de dahil ediyorum ve son çıktı grubu bu değeri hesaplamanın ne kadar sürdüğünü gösteriyor):

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 bayt

EDIT: Bu kodun orijinal sürümleri bazı numaralar için hatalı çıktı üretecektir, bu düzeltildi.

Buradaki her sorguda, ilk virgülden önce hesaplanacak numarayı ekleyin.

Herkes T-SQL'in en iyi golf dili olduğunu biliyor. İşte son test senaryosunu bile hesaplayacak bir versiyon. Test ettiğim makinede, bir saniyenin altında kaldı, herkes için nasıl çalıştığını görmek isterdim.

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

Ve burada yine, ama okunabilir:

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

Yalnızca ints kullanırsam, bu 157 byte'ta çıkan biraz daha kısa olabilir:

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

Ve bir kez daha, daha okunaklı:

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

Unutmayın @, sql'de geçerli bir tanımlayıcıdır ve muhtemelen Char(8000) nvarchar'dan (max) daha ucuz olanlardan kurtulabilirsiniz . Ayrıca charbunun yerine dönüştürebilir varcharveya strişlevi kullanabilirsiniz .
Michael B,

@MichaelB Oh, kullandığımı düşündüm @, aptalca beni. CHAR(8000)Danışma oldukça iyidir, bunu deneyeceğim. STR()Başınız için teşekkürlerin varlığını her zaman unutmuş gibiyim.
PenutReaper

aslında yardımcı olmuyor. Bununla birlikte, CTE'den sonraki parçayı select @t=concat(@t,@/i)daha küçük olması gereken :: içine yeniden yazabilirsiniz . Gerçi sql2012 gerektirir.
Michael B,

@MichaelB ah. CONCAT, Ben 2008 yaşıyorum. Bu yüzden şu anda bir SQL keman kullanmadan test edemiyorum. Yine de iyi çağrı.
PenutReaper

3

Turing Makine Kodu, 333 293 bayt

Burada kullanılan kodlamayı kullanıyorum .

Bu makine 9 durum ve 11 renk kullanır.

İkili girişe izin veriliyorsa, bu işlem, işlem sırasında birkaç on byte tasarruf sağlayarak yalnızca 4 renge düşürülebilir.

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

Yukarıdaki bağlantı çalışmıyorsa (bazen benim için çalışıyorsa, sayfanın yüklenmesini reddettiği zamanlarda) bu java uygulamasını kullanarak da test edebilirsiniz .


2

Perl, 66 bayt

STDIN üzerinden numara girişi yapılacaktır.

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

Çözümünüzün nasıl çalıştığını açıklayabilir misiniz? Neye ihtiyacın nasıl görmüyorum (.?)içinde $2bu yana (.*)içinde $1açgözlü ve ilk bu karakteri almalısınız. Ancak kaldırılırsa, kod artık doğru sonuçları vermez! Bu arada, finale ihtiyacınız yok ;.
CJ Dennis

@CJDennis Kaydedilen bu bayt için teşekkürler. Neyse,. orada rakam yok ise (örneğin 20) rakam ikiden hemen önce gelecektir. 120 veya 10020 gibi durumlarda, regex şu şekilde gruplanır: () (1) 2 (0) ve (10) (0) 2 (0). Daha sonra ilk grup basitçe yoksayılır, ikinci grup (mümkün olduğunda veya boş olduğunda her zaman bir rakamdır) artırılır ve üçüncü grup (her zaman sıfırdan oluşan) dikkate alınmaz ve bir sıfır eklenir. OEIS girişini bu regex için kılavuz olarak kullandım.
Frederick

Ben 53 bayt aşağı kodu var: $c=<>;s/(.*)2(.*)/$1+1 .$2.0/e||$_++while($c--);print. Haklıydım, (.?)asla bir şey yakalamadım.
CJ Dennis

$_=1;$c=<>;s/(.?)2/1+$1.0/e||$_++while(--$c);print50 bayt olan optimize edilebilir . .*Sadece orijinal metinle değiştirirseniz, başında veya sonunda, optimizasyon yapılabilir. Ayrıca, orjinalinde daima sıfır olduğu için 0 değerini sonuna eklemek için hiçbir sebep yoktur $3.
Thraidh

2

Pyth, 19 bayt

m/=%Qtydtd^L2_SslhQ

Logaritmik karmaşıklık. Gerekli sürede kolayca tamamlanır. Rakam listesi şeklinde çıktı.

Gösteri .


2

Perl, 84 70 67 bayt

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

Çok golf değil, daha iyi olsun ama çok hızlı çalışıyor!

Dennis'in önerisi 51'e düşürüyor (50 bayt + -p anahtarı)

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

Bu gerekir gibi çağrılabilir perl -p skew_binary.pl num_list.txtnereye num_list.txtüzerine kodlamak için numara ile tek bir satır içerir.


@frederick koltukları kenarında 2 için bekliyoruz
Robert Grant

@RobertGrant Yorumunu iki şeyden bir şeye aktardı!
CJ Dennis

İki şey: 1. $ ARGV [0] kullanmak yerine, girdi olarak <> kullanın. Argüman olarak herhangi bir dosya yoksa, stdin'den girdi alacaktır. 2. Bunun gibi tek sayma şemaları için normal ifadeler kullanın. Garip matematik işlemleri yapmak yerine, rakamları rakam gibi bir karakter dizisi gibi değiştirebilirsiniz. En iyi bölüm, tamamen basamaklardan oluşan bir dize olması koşuluyla, aynı zamanda matematik işlemlerini (artım gibi) kullanabilmenizdir. Normal ifade operatörlerinin belgelerine bakın, çünkü çoğu zaman çok yararlı olabilirler.
Frederick

Maalesef enter tuşuna bastım ve yorumu tamamlamadan önce kaydettim.
Frederick

@frederick çok mütevazı olma. Ne olduğunu biliyoruz!
Robert Grant,

1

Mathematica, 65

Oldukça hızlı olmalı, itiraf etmeliyim ki, bunu yapmadan önce diğer sunumlara göz attım.

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

Kullanımı:

f[1000000000000000000]

Çıktı:

11011110000010110110101100111010011101100100000000000001102

10 ^ 228'den sonra bir yerde MaxExtraPrecision hata mesajları vermeye başladı (bunun sonucunu makinemde .03 saniyede hesaplıyor)

MaxExtraPrecision sınırını kaldırdıktan sonra, bir saniyede yaklaşık 10 ^ 8000 değerine kadar sayıları işleyecektir.

Giriş:

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

Çıktı:

{1.060807, Null}

1

C, 95 bayt

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

Bu sayıları döndürmek için bir tamsayı ve bir arabellek kabul eder. Sonuçlar (çıktıda bulunamaz) bdeğeri ile sonlandırılarak saklanır 3. Girişini ele almak zorunda değiliz 0(soru sadece pozitif tamsayılar belirtildiği gibi), bu nedenle boş çıktıyı önlemek için özel bir kılıf yoktur.

Genişletilmiş kod

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

En anlamlı rakamdan başlayarak ardışık çıkarma işlemiyle çalışırız. Tek komplikasyon, mbaştaki sıfırları yazdırmamak için değişkeni kullanmamızdır . unsigned long longİstenirse 10 bayt pahasına doğal bir uzatma yapılabilir.

Test programı

Komut argümanlarına dönüştürülecek sayıları iletin. Bu dönüştürür intbasılabilir basamak dizesine dizi tamponu. Çalışma zamanı giriş için bir milisaniyeden az 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;
}

Test sonuçları

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

Sanırım bir C ++ sürümü benzer, ancak auto a=~0ullküçük bir avantaj için kullanabilir ...
Toby Speight


0

CoffeeScript, 92 69 bayt

Qwertiy'in cevabı ve güncellemelerine dayanarak :

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


@Qwertiy Cevabınıza atıfta bulundum ve her iki cevapta da,
regex'deki

Bütün olay değiştirilir. Neden grubun içinde olmak zorundasın? JS sürümü Firefox'ta parantez olmadan çalışır.
Qwertiy

0

Japt , 31 bayt

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

Çevrimiçi deneyin!

Neredeyse doğrudan liman Bu JS çözümünün . Daha iyi bir yol olup olmadığını bilmiyorum.

Ambalajsız ve Nasıl Çalışır?

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 bayt

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

Koş ve hata ayıkla

Resmi karmaşıklık sınıfının tam olarak ne olduğundan emin değilim, ancak tüm test durumlarını bu makinede saniyenin onda birinde yapmak için yeterince hızlı.

Ambalajsız, ağzı açılmış ve yorumlanmış gibi görünüyor. Bu programda, x register başlangıçta girişi içerir.

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

Bunu çalıştır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.