Đánh số trang kiểu xkcd


65

Cuốn sách "xkcd, tập 0" của Randall Munroe sử dụng hệ thống số khá kỳ lạ cho số trang. Một vài số trang đầu tiên là

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

Điều này có vẻ hơi giống ternary, nhưng nhận thấy rằng ông bỏ qua từ 20thẳng đến 100, từ 120đến 200và đi từ 200đến 1000. Một cách để xác định chuỗi này là nói rằng nó liệt kê tất cả các số thứ ba có chứa nhiều nhất một 2và không 1sau đó 2. Bạn có thể tìm thấy điều này trên OEIS trong mục A169683 . Hệ thống số này được gọi là nhị phân xiên .

Nhiệm vụ của bạn là tìm đại diện của một số nguyên dương cho trước Ntrong hệ thống số này.

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm và xuất kết quả qua tham số STDOUT (hoặc thay thế gần nhất), tham số trả về hàm hoặc tham số hàm (out).

Đầu ra có thể là một chuỗi, một số có biểu diễn thập phân bằng với biểu diễn nhị phân nghiêng hoặc danh sách các chữ số (dưới dạng số nguyên hoặc ký tự / chuỗi). Bạn không được trả về số không hàng đầu.

Đây là mã golf, vì vậy câu trả lời ngắn nhất (tính bằng byte) sẽ thắng.

Thực tế thú vị: Thực sự có một số công đức cho hệ thống số này. Khi tăng một số, bạn sẽ luôn thay đổi tối đa hai chữ số liền kề - bạn sẽ không bao giờ phải thực hiện thay đổi trong toàn bộ số. Với biểu diễn đúng cho phép tăng dần trong O (1).

Các trường hợp thử nghiệm

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

Tôi sẽ đưa ra một tiền thưởng cho câu trả lời ngắn nhất có thể giải quyết trường hợp thử nghiệm cuối cùng (và bất kỳ đầu vào nào khác có cường độ tương tự, vì vậy đừng nghĩ về việc mã hóa nó) trong chưa đầy một giây.

Bảng xếp hạng

Dưới đây là Stack Snippet để tạo cả bảng xếp hạng thông thường và tổng quan về người chiến thắng theo ngôn ngữ.

Để đảm bảo rằng câu trả lời của bạn hiển thị, vui lòng bắt đầu câu trả lời của bạn bằng một tiêu đề, sử dụng mẫu Markdown sau:

# Language Name, N bytes

nơi Nlà kích thước của trình của bạn. Nếu bạn cải thiện điểm số của mình, bạn có thể giữ điểm số cũ trong tiêu đề, bằng cách đánh bại chúng thông qua. Ví dụ:

# 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
Tôi đã có cuốn sách đó kể từ khi nó ra mắt và không bao giờ chú ý đến việc đánh số trang.
Alex A.

2
@AlexA. Tôi có nó trên Kindle của tôi, nơi bạn không thể thực hiện bất kỳ đánh số trang thú vị nào.
LegionMammal978

21
@ LegionMammal978: Đáng thương.
Alex A.

1
@ SuperJedi224 Đồng thuận dường như là không , rất xin lỗi (Tôi sẽ ngoại lệ với sự đồng thuận nếu đó là loại đầu vào duy nhất mà ngôn ngữ của bạn có thể xử lý, nhưng dường như không phải vậy).
Martin Ender

4
Điều này nhắc nhở tôi về cách tôi từng đếm khi tôi lên 3. Tôi lý luận: "không có năm mươi mười, vì vậy sau một trăm chín phải là hai trăm." Tôi chỉ nhận ra sai lầm của mình khi thấy sự khác biệt giữa 59->60109->110, với thêm 0.
Cyoce

Câu trả lời:


12

Bình thường, 17 byte

Ljb3ye.f!-P-yZ01Q

Điều này hơi chậm một cách nực cười - O(output^log_2(3)). Đó là số mũ theo độ dài của đầu vào, nhưng không phải theo cấp số nhân, như một số câu trả lời trên trang. Một số ý tưởng lấy từ câu trả lời của @ Dennis, tại đây .

Trình diễn, thuyết trình.

Nó sử dụng .fchức năng "lặp cho đến khi tìm thấy n khớp" của Pyth.


32

CJam, 24 23 22 21 19 byte

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

Đây là cách tiếp cận O (log n) , trong đó n là đầu vào, hoàn thành trường hợp thử nghiệm cuối cùng ngay lập tức. Nó chuyển đổi n trực tiếp thành xiên nhị phân, sử dụng phép chia mô đun theo các giá trị của chữ số 1 .

Mã này kết thúc với một lỗi xảy ra với STDERR với trình thông dịch Java, được cho phép theo sự đồng thuận trên Meta .

Nếu bạn thử mã này trong trình thông dịch CJam , chỉ cần bỏ qua mọi thứ trừ dòng đầu ra cuối cùng.

Các lỗi có thể được loại bỏ, phải trả giá bằng 2 byte, bởi prepending 2>tới W%.

Cảm ơn @ MartinBüttner vì đã chơi golf một byte.

Lý lịch

Biểu diễn nhị phân nghiêng a k ... a 0 tương ứng với số nguyên n = (2 k + 1 -1) a k + ... + (2 1 -1) a 0 .

Vì cả (2 k -1) + ... + (2 1 -1) = 2 k + 1 - (k + 2)(2 k -1) + ... + 2 (2 j -1) = 2 k + 1 - (2 j + 1 - 2 j + k + 1) là ít hơn 2 k + 1 -1 , các giá trị của một k để một 0 có thể được phục hồi bằng cách phân chia mô-đun liên tiếp bởi 2 k + 1 -1 , 2 k -1 , v.v.

Để bắt đầu, chúng ta phải tìm giá trị 2 k + 1 -1 trước. Vì n nhiều nhất là 2 (2 k + 1 -1) , nên số nguyên n + 1 phải nhỏ hơn 2 k + 2 .

Do đó, lấy phần nguyên của logarit nhị phân của n + 1 mang lại k + 1 .

Cuối cùng, chúng tôi quan sát rằng số nguyên n + 1⌊log 2 (n + 1) ⌋ chữ số trong cơ sở 2.

Làm thế nào nó hoạt động

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#

Trong hai lần lặp cuối cùng, chúng tôi thực hiện phép chia mô-đun cho 10 . Đầu tiên đẩy 0 không mong muốn trên ngăn xếp. Các nỗ lực cuối cùng để thực thi 0 0 md, xuất hiện cả 0 giây không mong muốn từ ngăn xếp, thoát ra ngay lập tức thay vì đẩy bất cứ thứ gì và đưa ngăn xếp vào 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)

Có vẻ để làm việc cho các trường hợp thử nghiệm nhất định. Nếu tôi đã đúng, đây sẽ là vấn đề O(place values set in output), vì vậy đây là trường hợp cuối cùng một cách dễ dàng.

Gọi như thế f(100). Trả về một đại diện thập phân bằng nhị phân nghiêng.

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]

Hơi kém hiệu quả nhưng vẫn logarit, vì vậy trường hợp cuối cùng là gần như ngay lập tức.

Gọi như thế g(100). Trả về một danh sách các chữ số.


không 2andbiên dịch trong 3? Tôi đang ở 2 và 2and2ném lỗi cú pháp
TankorSmash

3
@TankorSmash 2and2sẽ không hoạt động vì nó được phân tích cú pháp dưới dạng 2 and2- thử 2and 2, sẽ hoạt động nếu phiên bản Python của bạn đủ mới (được thử nghiệm trong Python 2.7.10)
Sp3000

Oh tốt, bạn đúng. Ngay cả trên 2.7.3 nó cũng hoạt động.
TankorSmash

12

CJam, 22 21 20 byte

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

Đây là cách tiếp cận O (e n n) , trong đó n là đầu vào. Nó liệt kê đầu tiên ⌊e n số nguyên không âm trong cơ sở 3, loại bỏ những người có 2 s hoặc 1 s sau khi người đầu tiên 2 (nếu có) và chọn n + 1 thứ .

Hãy thử trực tuyến trong trình thông dịch CJam .

Làm thế nào nó hoạt động

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

Bình thường, 20 byte

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

Chạy trong O (log (input ())), dưới một giây cho trường hợp thử nghiệm cuối cùng. Dựa trên một vòng chạy cho đến khi lỗi. Không có dòng mới.

Trình diễn, thuyết trình.

Giải trình:

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 được khởi tạo thành giá trị của vị trí chữ số nhị phân lệch nhỏ nhất lớn hơn đầu vào. Sau đó, mỗi lần qua vòng lặp, chúng tôi thực hiện như sau:

  • Xóa từng chữ số giá trị Jtừ Qvới =%QJ. Chẳng hạn, nếu Q=10J=7, Qtrở thành 3, tương ứng với nhị phân lệch thay đổi từ 110thành 10. Điều này không có hiệu lực trong lần lặp đầu tiên.
  • Thay đổi Jgiá trị cơ sở nhị phân xiên nhỏ hơn tiếp theo với =/J2. Điều này được phân chia theo 2, thay đổi J=7thành J=3, ví dụ. Bởi vì điều này xảy ra trước khi chữ số đầu tiên là đầu ra, Jđược đặt ở vị trí một chữ số cao hơn mức cần thiết.
  • Tìm giá trị chữ số thực với /QJ(hiệu quả).
  • In giá trị đó bằng p, thay vì in mặc định của Pyth, để tránh dòng mới.

Vòng lặp này sẽ lặp lại cho đến khi Jtrở thành số không, tại đó một lỗi chia cho số 0 sẽ được ném và vòng lặp sẽ kết thúc.


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)

Cách sử dụng là: f(1048576)=> `" 10000000000000000001 "

Kiểm tra đối số cuối cùng trong tình trạng nguy hiểm của riêng bạn. Tôi đã bỏ cuộc sau 5 giây.

Và in đẹp với ý kiến!

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, các chức năng không tên là hoàn toàn chấp nhận được, vì vậy bạn không cần 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

@nderscore Khá tuyệt: D
La bàn

1
-7 byte nếu bạn sử dụng ES7: thay thế Math.pow(3,s.length+c)bằng 3**(s.length+c).
Gustavo

3
@GustavoRodrigues Tôi thậm chí còn chưa học xong ES6! @ _ @
La bàn

7

Võng mạc, 55 byte

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

Đưa đầu vào trong unary.

Mỗi dòng nên đi đến tệp riêng của nó nhưng bạn có thể chạy mã dưới dạng một tệp có -scờ. Ví dụ:

> echo 11111|retina -s skew
12

Phương pháp: Thực hiện gia số trên số lần nhập chuỗi bắt đầu từ chuỗi 0.

Chúng tôi sử dụng các quy tắc tăng sau:

  • nếu chứa 2: ^2 -> ^12; 02 -> 12;12 -> 20
  • nếu không chứa 2: 0$ -> 1$;1$ -> 2$

(Có thể có nhiều nhất một 2chuỗi trong chuỗi; ^$đánh dấu điểm bắt đầu và kết thúc của chuỗi trong quy tắc.)

Thêm thông tin về 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;}

Câu trả lời này có dạng một hàm ẩn danh duy nhất nhận một đối số nguyên và trả về câu trả lời dưới dạng Chuỗi. Dưới đây là một lớp hoàn chỉnh để thử nghiệm giải pháp này.

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}

Đây là một bác sĩ vũ phu, vì vậy nó khá chậm đối với số lượng lớn hơn.

Đầu ra:

$ ./xkcdnum.sh 1000
111110120
$ 

5

Java, 337 335 253 246 244 byte

Một phương thức lấy chỉ mục là a longvà trả về kết quả dưới dạng chuỗi

Sử dụng một longchỉ mục để về mặt lý thuyết có thể xử lý trường hợp thử nghiệm cuối cùng, nhưng tôi thực sự không đề xuất nó.

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
Bạn có thể rút ngắn điều này khá nhiều bằng cách biến nó thành một hàm thay vì một chương trình đầy đủ (và lấy đầu vào làm đối số thay vì từ Máy quét).
Geobits

2
Bạn không cần dấu ngoặc trong if(j == 0) câu lệnh (bốn byte). Bạn không cần phải khai báo k; bạn chỉ có thể sử dụng jlại (bốn cái nữa). Bạn có thể sử dụng suy luận kiểu chung (trong Java 7) trong khai báo Danh sách của bạn ( new ArrayList<>();) (4 khác)
durron597

4

Haskell, 73 72

Cảm ơn @nimi cho 1 byte!

Giải pháp này sẽ không giành được bất kỳ tiền thưởng nào, các bài kiểm tra cuối cùng mất một lượng thời gian không đáng có để chạy, nhưng, tôi nghĩ rằng tôi đã chơi golf khá tốt.

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

Giải pháp này là một cách tiếp cận khá ngây thơ, tính toán số nhị phân lệch nbằng cách tăng 0 nlần.


4

CJam, 24 byte

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

Đây là cách tiếp cận O (n log n) , trong đó n là đầu vào. Nó bắt đầu với biểu diễn nhị phân xiên bằng 0 và tăng số nguyên n tương ứng .

Hãy thử trực tuyến trong trình thông dịch CJam .

Lý lịch

Tăng một số trong nhị phân nghiêng có thể được thực hiện bằng hai bước đơn giản sau:

  1. Thay thế 2 cuối cùng bằng 0 .

  2. Nếu số 2 đã được thay thế, hãy tăng chữ số sang trái.

    Nếu không, tăng chữ số cuối cùng.

Làm thế nào nó hoạt động

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

Toán học của tôi không hiệu quả và việc chơi golf của tôi có thể sử dụng công việc. Nhưng đó là nỗ lực đầu tiên của tôi tại PoG và nghĩ rằng tôi sẽ thử cái này. Sắp xếp một cách Brute Force mặc dù.

Nó chỉ đếm bằng 1 trừ khi chữ số cuối cùng là 2 rồi lùi lại 2 và nhảy về phía trước 10. Cộng với dấu 0.

Điều này dừng hoạt động ở 65534 vì VBA khăng khăng đưa ra đầu ra theo ký hiệu khoa học, nhưng logic sẽ hoạt động tốt đối với các số thậm chí cao hơn

Nhìn về các đề xuất chơi gôn, VBA không thân thiện với golf nhưng nó không thường được đại diện và tôi nghĩ rằng nó có thể đánh bại Java trong thời gian dài.

Edit1: Cảm ơn Manu vì đã giúp cạo sạch 62 byte

Edit2: hoán đổi debug.printcho msgboxlà đầu ra. Đã lưu 5 byte


1
Bạn có thể loại bỏ các dấu ngoặc từ Debug.Print (q). Ngoài ra, bạn có thể xóa hầu hết các khoảng trắng (trình chỉnh sửa sẽ đưa chúng trở lại, nhưng chúng không cần thiết). Bạn không cần phải khai báo k as Long, chỉ cần viết k. Nó sẽ là một biến của kiểu Biến và mã sẽ vẫn hoạt động. Với những lời khuyên này, bạn sẽ nhận được tới ~ 165 byte.
CommonGuy

Một số suy nghĩ khác: Bạn có thể bỏ qua đối số đầu tiên và cuối cùng InStr, chúng là tùy chọn. Trim()không cần thiết, vì bạn không có khoảng trắng. Áp dụng đúng, tôi nhận được tới 147 byte .
CommonGuy

1
Cảm ơn Manu trợ giúp, Một câu hỏi nhanh, Đầu ra phải là Đầu ra tiêu chuẩn. Tôi không chắc điều gì sẽ xảy ra trong VBA. debug.print qsẽ là đầu ra tiêu chuẩn? msgbox qngắn hơn nhưng Again có vẻ như nó không hoàn toàn là đầu ra tiêu chuẩn. Sheet1.cells(1,1)có vẻ như đầu ra điển hình nhưng giả sử nó chạy trong excel. Tôi chỉ không chắc chắn về cách chơi golf mã nghiêm ngặt về những thứ này.
JimmyJazzx

Xin chúc mừng, bạn đã đánh bại câu trả lời java;) Tôi cũng không biết ... Chỉ cần sử dụng MsgBox, nếu ai đó phàn nàn, bạn vẫn có thể thay đổi lại.
CommonGuy

4

Javascript ES6, 99 86 78 76 72 ký tự

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}

Kiểm tra:

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

Thực tế thú vị: Thực sự có một số công đức cho hệ thống số này. Khi tăng một số, bạn sẽ luôn thay đổi tối đa hai chữ số liền kề - bạn sẽ không bao giờ phải thực hiện thay đổi trong toàn bộ số. Với biểu diễn đúng cho phép tăng dần trong O (1).

Cảm ơn bạn vì sự thật - đó là cơ sở cho giải pháp của tôi :)


Làm thế nào tôi có thể để lại niềng răng không cần thiết trong regex? o_O
Qwertiy

3

Octave, 107 101 byte

Nên là O (log n) nếu tôi nhận ra điều này đúng ...

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

In đẹp

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

Tôi hơi bị cản trở khi giải quyết thử thách cuối cùng, vì Octave mặc định coi mọi thứ là số dấu phẩy động và tôi không có độ chính xác cần thiết để tính toán cái cuối cùng. Tôi đã khắc phục điều đó bằng cách chi tiêu các byte quý giá để buộc mọi thứ phải là một số nguyên không dấu. Kết quả của cái cuối cùng là quá lớn để coi là một số, vì vậy kết quả là một chuỗi.

Đầu ra (Tôi bao gồm 1e18 - 1để hiển thị Tôi có thể làm điều đó một cách chính xác và bộ đầu ra cuối cùng cho biết thời gian để tính giá trị đó là bao lâu):

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: Các phiên bản gốc của mã này sẽ tạo ra đầu ra không chính xác cho một số số, điều này đã được sửa.

Với mỗi truy vấn ở đây, chỉ cần thêm số để tính trước dấu phẩy đầu tiên.

Mọi người đều biết rằng T-SQL là ngôn ngữ chơi golf tốt nhất. Đây là một phiên bản sẽ tính toán ngay cả trường hợp thử nghiệm cuối cùng. Trên máy tôi đã thử nó, nó chạy trong chưa đầy một giây, tôi rất muốn xem nó chạy như thế nào cho những người khác.

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

Và đây là một lần nữa, nhưng có thể đọc được:

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

Nếu tôi chỉ sử dụng ints, điều này có thể ngắn hơn một chút, xuất hiện ở mức 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

Và một lần nữa, dễ đọc hơn:

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

Nhớ @là một định danh hợp lệ trong sql và rất có thể bạn có thể thoát khỏi Char(8000) mà vẫn rẻ hơn nvarchar (tối đa). Bạn cũng có thể chuyển đổi sang charthay vì varcharhoặc sử dụng strchức năng.
Michael B

@MichaelB Ồ, tôi nghĩ rằng tôi đã sử dụng @, ngớ ngẩn với tôi. Các CHAR(8000)lời khuyên là khá tốt, tôi sẽ cố gắng đó. Tôi dường như luôn quên về sự tồn tại của STR()lời cảm ơn cho những người đứng đầu.
PenutReaper

không thực sự giúp đỡ. Tuy nhiên, bạn có thể viết lại phần sau CTE thành :: select @t=concat(@t,@/i)nên nhỏ hơn. Yêu cầu sql2012 mặc dù.
Michael B

@MichaelB ah. CONCAT, Tôi vào năm 2008. Vì vậy, tôi không thể kiểm tra nó mà không cần sử dụng SQL fiddle ngay bây giờ. Cuộc gọi tốt mặc dù.
PenutReaper

3

Mã máy Turing, 333 293 byte

Tôi đang sử dụng một mã hóa như được sử dụng ở đây .

Máy này sử dụng 9 trạng thái và 11 màu.

Nếu đầu vào nhị phân được cho phép, điều này có thể được giảm xuống chỉ còn 4 màu, tiết kiệm vài chục byte trong quy trình.

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

Nếu liên kết trên không hoạt động (đôi khi nó hoạt động với tôi, lần khác trang sẽ từ chối tải), bạn cũng có thể kiểm tra điều này bằng cách sử dụng java này.


2

Perl, 66 byte

Số sẽ được nhập thông qua STDIN.

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

Bạn có thể giải thích làm thế nào giải pháp của bạn hoạt động? Tôi không thấy làm thế nào bạn cần (.?)trong $2từ (.*)trong $1nên tham lam và nhận được nhân vật mà đầu tiên. Nhưng nếu nó bị xóa, mã sẽ không tạo ra kết quả chính xác nữa! Nhân tiện, bạn không cần trận chung kết ;.
CJ Dennis

@CJDennis Cảm ơn vì đã lưu byte đó. Dù sao, cái? sẽ có được chữ số đến ngay trước hai chữ số trừ khi không có chữ số ở đó (ví dụ 20). Trong các trường hợp như 120 hoặc 10020, các nhóm regex như thế này: () (1) 2 (0) và (10) (0) 2 (0). Sau đó, nhóm thứ nhất được bỏ qua đơn giản, nhóm thứ hai (luôn luôn là một chữ số nếu có thể hoặc trống) được tăng lên và nhóm thứ ba (luôn bao gồm các số 0) được bỏ qua và thêm vào số 0. Tôi chỉ đơn giản sử dụng mục OEIS làm hướng dẫn cho regex này.
frederick

Tôi đã nhận được mã của bạn xuống còn 53 byte : $c=<>;s/(.*)2(.*)/$1+1 .$2.0/e||$_++while($c--);print. Tôi đã đúng, (.?)không bao giờ nắm bắt bất cứ điều gì.
CJ Dennis

Có thể được tối ưu hóa $_=1;$c=<>;s/(.?)2/1+$1.0/e||$_++while(--$c);print, đó là 50 byte. .*ở đầu hoặc cuối có thể được tối ưu hóa đi, nếu bạn chỉ thay thế nó bằng văn bản gốc. Ngoài ra, không có lý do để thêm 0 vào cuối, vì luôn luôn chỉ có các số 0 trong bản gốc $3.
Thearh

2

Bình thường, 19 byte

m/=%Qtydtd^L2_SslhQ

Độ phức tạp logarit. Dễ dàng kết thúc trong khoảng thời gian cần thiết. Đầu ra dưới dạng một danh sách các chữ số.

Trình diễn .


2

Perl, 84 70 67 byte

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

Không chơi gôn lắm, trở nên tốt hơn nhưng nó hoạt động rất nhanh!

Đề xuất của Dennis giảm xuống 51 (chuyển đổi 50 byte + -p)

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

phải được gọi như perl -p skew_binary.pl num_list.txtnơi num_list.txtchứa một dòng duy nhất với số để mã hóa trên đó.


@frederick chúng tôi đang chờ đợi 2.
Robert Grant

@RobertGrant Anh ấy đã đánh giá nhận xét của mình từ hai điều này sang một điều khác!
CJ Dennis

Hai điều: 1. Thay vì sử dụng $ ARGV [0], hãy sử dụng <> làm đầu vào. Nó sẽ lấy đầu vào từ stdin trừ khi có bất kỳ tệp nào làm đối số. 2. Đối với các sơ đồ đếm lẻ như thế này, hãy sử dụng các biểu thức chính quy. Thay vì thực hiện các phép toán lẻ, bạn có thể thay thế các chữ số trong một số như thể đó là một chuỗi. Phần tốt nhất là bạn có thể sử dụng các phép toán (như gia số) trên nó cùng một lúc, với điều kiện đó là một chuỗi bao gồm hoàn toàn các chữ số. Kiểm tra tài liệu cho các toán tử biểu thức chính quy, vì chúng có thể rất hữu ích trong nhiều trường hợp.
frederick

Xin lỗi, tôi nhấn enter và nó đã lưu trước khi tôi hoàn thành bình luận.
frederick

@frederick đừng quá khiêm tốn. Chúng tôi biết những gì đã xảy ra!
Robert Grant

1

Toán học, 65

Nên khá nhanh, mặc dù tôi phải thừa nhận tôi đã xem lén các bài nộp khác trước khi thực hiện.

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

Sử dụng:

f[1000000000000000000]

Đầu ra:

11011110000010110110101100111010011101100100000000000001102

Bắt đầu đưa ra thông báo lỗi MaxExtraPrecision ở đâu đó trong vòng 10 ^ 228 (trong đó tính toán kết quả trong 0,03 giây trên máy của tôi)

Sau khi xóa giới hạn MaxExtraPrecision, nó sẽ xử lý các số lên tới khoảng 10 ^ 8000 trong một giây.

Đầu vào:

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

Đầu ra:

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

Điều này chấp nhận một số nguyên và một bộ đệm để trả về các chữ số. Các kết quả được lưu trữ trong b, kết thúc bằng giá trị 3(không thể xảy ra trong đầu ra). Chúng tôi không phải xử lý đầu vào của 0(như câu hỏi chỉ xác định số nguyên dương), vì vậy không có vỏ bọc đặc biệt để tránh đầu ra trống.

Mã mở rộng

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

Chúng tôi hoạt động bằng phép trừ liên tiếp, bắt đầu bằng chữ số có ý nghĩa nhất. Sự phức tạp duy nhất là chúng tôi sử dụng biến mđể tránh in các số không hàng đầu. Một phần mở rộng tự nhiên unsigned long longcó thể được thực hiện nếu muốn, với chi phí 10 byte.

Chương trình kiểm tra

Truyền số để được chuyển đổi làm đối số lệnh. Nó chuyển đổi intbộ đệm mảng thành một chuỗi chữ số có thể in được. Thời gian chạy ít hơn một phần nghìn giây cho đầu vào 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;
}

Kết quả kiểm tra

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

Tôi đoán một phiên bản C ++ tương tự, nhưng có thể sử dụng auto a=~0ullcho một lợi thế nhỏ ...
Toby Speight


0

CoffeeScript, 92 69 byte

Dựa trên câu trả lời và cập nhật của 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
Chuyển đổi sang ngôn ngữ khác mà không cần tối ưu hóa đơn giản bằng cách loại bỏ các dấu ngoặc không cần thiết trong regex có vẻ không hay đối với tôi ...
Qwertiy

@Qwertiy Tôi đã cung cấp ghi nhận cho câu trả lời của bạn và với cả hai câu trả lời tôi không thể tạo ra kết quả giống nhau mà không có dấu ngoặc trong regex
rink.attguard.6

Toàn bộ sự xuất hiện được thay thế. Tại sao bạn cần nó ở trong nhóm? Phiên bản JS hoạt động trong Firefox mà không có dấu ngoặc.
Qwertiy

0

Japt , 31 byte

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

Hãy thử trực tuyến!

Hầu như cổng trực tiếp của giải pháp JS này . Không có ý tưởng nếu có cách tốt hơn.

Giải nén & Cách thức hoạt động

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█ò

Chạy và gỡ lỗi nó

Tôi không chắc chính xác lớp phức tạp chính thức là gì, nhưng nó đủ nhanh để thực hiện tất cả các trường hợp thử nghiệm trong một phần mười giây trên máy này.

Giải nén, không được chỉnh sửa, và nhận xét, nó trông như thế này. Trong chương trình này, thanh ghi x ban đầu chứa đầu vào.

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

Chạy cái này

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.