Độ dài đếm ngược nhị phân


18

lấy cảm hứng từ đếm ngược từ vô cực

Cho một số nguyên không âm N , xuất số lần lặp lại của các bước sau để đạt 0:

  1. Đổi N thành nhị phân ( 4812390 -> 10010010110111001100110)
  2. Lật từng bit (10010010110111001100110 -> 01101101001000110011001 )
  3. Cắt số 0 hàng đầu (01101101001000110011001 -> 1101101001000110011001 )
  4. Chuyển đổi lại thành số thập phân (1101101001000110011001 -> 3576217 )

Quy tắc

  • Đầu vào và đầu ra có thể ở bất kỳ định dạng nhất quán, rõ ràng nào
  • Đầu vào sẽ nằm trong phạm vi số nguyên có thể biểu thị riêng cho ngôn ngữ của bạn (nếu ngôn ngữ của bạn hỗ trợ các số nguyên lớn tùy ý, không có ràng buộc)

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

0 -> 0
1 -> 1
42 -> 6
97 -> 3
170 -> 8
255 -> 1
682 -> 10
8675309 -> 11
4812390 -> 14
178956970 -> 28
2863311530 -> 32

Trình tự này là A005811 trong OEIS.


6
Bước 3 hoàn toàn không sử dụng
edc65

@ edc65 Có vẻ như bạn có thể thực hiện bước 3 hoặc bước 4, tùy thuộc vào cách thuật toán của bạn được trình bày
Brian J

@ edc65 Có thể đối với bạn nó không có tác dụng. Một toán tử nghịch đảo đơn giản không cắt các số 0 hàng đầu cho bạn. ~(~a) == a
Chọc

@Poke Bitwise KHÔNG đảo ngược tất cả các bit của biểu diễn nhị phân, bao gồm các số 0 đứng đầu (và một số lượng vô hạn của chúng trong các ngôn ngữ có số nguyên chính xác tùy ý). Điều này không tương đương với bước 2.
Dennis

@Poke Một thao tác nghịch đảo đơn giản khác với việc áp dụng các bước 1..4. Nếu bạn muốn áp dụng các bước này, bước 3 không có tác dụng, vì việc lật ở bước 2 (như được hiển thị) không thay đổi các số 0 hàng đầu. Nếu bước 2 không thay đổi số 0 hàng đầu thành số 1 hàng đầu, thì thật đáng tiếc, bạn phải xóa số 1 hàng đầu trong bước 3, chứ không phải số 0
edc65

Câu trả lời:


14

Thạch , 6 4 byte

^HBS

Hãy thử trực tuyến! hoặc xác minh tất cả các trường hợp thử nghiệm .

Lý lịch

Đặt n là số nguyên không âm.

Bước 2 và 3 của quy trình được mô tả trong thông số kỹ thuật có thể được thay thế bằng cách loại bỏ tất cả các bit 1 hàng đầu và chuyển đổi các bit còn lại.

Điều này có nghĩa là chúng ta sẽ xóa chính xác một nhóm các chữ số nhị phân liền kề và bằng nhau trong mỗi lần lặp, do đó, Độ dài đếm ngược nhị phân của n chỉ là số của các nhóm này trong biểu diễn nhị phân của n . Đối với mục đích của thử thách này, hãy nghĩ về 0 là không có chữ số.

Với n = 8675309 , quá trình này trông như sau trong hệ nhị phân.

100001000101111111101101
 11110111010000000010010
     1000101111111101101
      111010000000010010
         101111111101101
          10000000010010
           1111111101101
                   10010
                    1101
                      10
                       1
                       0

Thay vì đếm các nhóm này (sẽ thất bại cho trường hợp cạnh 0 ), chúng tôi thực hiện như sau.

nn: 2 có các biểu diễn nhị phân sau.

n   = 8675309 = 100001000101111111101101_2
n:2 = 4337654 =  10000100010111111110110_2

Lưu ý rằng biểu diễn nhị phân của n: 2 chỉ đơn giản là n , được dịch một bit sang trái.

Nếu chúng tôi XOR nn: 2 , chúng tôi sẽ nhận được 1 (MSB) và thêm 1 cho mỗi cặp chữ số liền kề khác nhau. Do đó, số lượng các nhóm bằng với số bit được đặt trong n n: 2 .

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

^HBS  Main link. Argument: n

 H    Halve; yield n:2.
^     XOR n with n:2.
  B   Convert the result to binary.
   S  Compute the sum of the resulting binary digits.

1
Kinh ngạc! Một lý do hoàn toàn khác
edc65

9

Python 2, 30 byte

lambda n:bin(n^n/2).count('1')

Kiểm tra nó trên Ideone .

Lý lịch

Để n là số nguyên không âm.

Bước 2 và 3 của quy trình được mô tả trong thông số kỹ thuật có thể được thay thế bằng cách loại bỏ tất cả các bit 1 hàng đầu và chuyển đổi các bit còn lại.

Điều này có nghĩa là chúng ta sẽ xóa chính xác một nhóm các chữ số nhị phân liền kề và bằng nhau trong mỗi lần lặp, do đó, Độ dài đếm ngược nhị phân của n chỉ là số của các nhóm này trong biểu diễn nhị phân của n . Đối với mục đích của thử thách này, hãy nghĩ về 0 là không có chữ số.

Với n = 8675309 , quá trình này trông như sau trong hệ nhị phân.

100001000101111111101101
 11110111010000000010010
     1000101111111101101
      111010000000010010
         101111111101101
          10000000010010
           1111111101101
                   10010
                    1101
                      10
                       1
                       0

Thay vì đếm các nhóm này (sẽ thất bại cho trường hợp cạnh 0 ), chúng tôi thực hiện như sau.

nn: 2 có các biểu diễn nhị phân sau.

n   = 8675309 = 100001000101111111101101_2
n:2 = 4337654 =  10000100010111111110110_2

Lưu ý rằng biểu diễn nhị phân của n: 2 chỉ đơn giản là n , được dịch một bit sang trái.

Nếu chúng tôi XOR nn: 2 , chúng tôi sẽ nhận được 1 (MSB) và thêm 1 cho mỗi cặp chữ số liền kề khác nhau. Do đó, số lượng các nhóm bằng với số bit được đặt trong n n: 2 .


9

Python 2, 29 byte

f=lambda n:n and-n%4/2+f(n/2)

Đếm số lượng xen kẽ giữa 0 và 1 trong khai triển nhị phân, tính số 1 thay thế là một thay thế. Làm như vậy bằng cách kiểm tra xem hai chữ số nhị phân cuối cùng có khác nhau không, sau đó đệ quy lên số có chữ số cuối cùng được loại bỏ. Hai chữ số cuối cùng khác nhau chính xác nếu n%4là 1 hoặc 2, có thể được kiểm tra là -n%4/2.


6

JavaScript (ES6), 26 byte

f=n=>n&&(n^(n>>=1))%2+f(n)

Hoạt động bằng cách đếm các chuyển đổi giữa 0 và 1. Chỉ hoạt động tối đa 31 bit. 29 byte để hỗ trợ 53 bit:

f=n=>1<=n&&(n%2^n/2%2)+f(n/2)



3

CJam , 14 byte

ri0{2b:!2bj)}j

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

ri      e# read integer
0       e# value for terminal case
{       e# recursive function
  2b    e#   create binary representation with no leading zeros
  :!    e#   flip bits
  2b    e#   convert binary back to integer
  j     e#   recursive call
  )     e#   increment from 0 on the way up
}j      e# end

Về cơ bản là một câu trả lời của tôi cho câu hỏi khác.


3

Java 7,112 108 100 90 73 byte

int c(int i){int l=1,j=i;for(;(j=j/2)>0;l*=2);return i<1?0:1+c(2*l-1-i);}

Ý kiến ​​cơ bản

 Lets take an no 10110(21)
 then you do set all bits in no 21 and you will get 11111
 and after that you would subtract the original number from 11111.
 You will get 01001 and loop it until you will get 0

j=j/2có thể rút ngắn thành j/=2. Ngoài ra một câu trả lời tuyệt vời!
Kevin Cruijssen

Hmm .. một cổng từ câu trả lời JavaScript của @Neil ngắn hơn: int c(int i){return i>0?((i^(i>>=1))%2+c(i):0;}( 47 byte ). Tôi vẫn sẽ để lại câu trả lời hiện tại của bạn, vì nó nguyên bản hơn và các cổng từ người dùng khác hoàn toàn trái ngược với bản gốc. :)
Kevin Cruijssen

3

J, 14 byte

**1+/@,2~:/\#:

Đếm số lần chạy trong các chữ số nhị phân của n với trường hợp đặc biệt trả về 0 cho n = 0.

Sử dụng

   f =: **1+/@,2~:/\#:
   (,.f"0) 0 1 42 97 170 255 682 8675309 4812390 178956970 2863311530
         0  0
         1  1
        42  6
        97  3
       170  8
       255  1
       682 10
   8675309 11
   4812390 14
 178956970 28
2863311530 32

Giải trình

**1+/@,2~:/\#:  Input: integer n
            #:  Get the binary digits of n
       2   \    For each overlapping sublist of size 2
        ~:/       Reduce by not-equals
  1   ,         Prepend a 1
   +/@          Reduce by addition
*               Sign(n), returns 0 for n = 0 else 1
 *              Multiply with the previous sum and return

3

CJam , 11 10 byte

Cảm ơn @Dennis vì đã tiết kiệm một byte!

ri_2be`,e&

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

Giải trình

ri            #e Read as integer
              #e STACK: 97
  _           #e Duplicate
              #e STACK: 97, 97
   2b         #e Convert to binary
              #e STACK: 97, [1 1 0 0 0 0 1]
     e`       #e Run-length encoding
              #e STACK: 97, [[2 1] [4 0] [1 1]]
       ,      #e Length
              #e STACK: 97, 3
        e&    #e Return first value if 0, or else the second value
              #e STACK: 3

1
e&(logic AND) lưu một byte qua \g*.
Dennis

@Dennis Cảm ơn! Thật tiện dụng khi logic và hoạt động của CJam, tôi không biết
Luis Mendo

2

Vợt 349 byte

(define(h s)(apply string(map(λ(x)(if(eq? x #\0)#\1 #\0))(string->list s))))(define(g s)(let*
((l(string-length s))(k(for/list((i s)(n l)#:final(not(equal? i #\0)))n)))(substring s(last k))))
(define(f n)(if(= 0 n)0(begin(let loop((n n)(c 1))(define m(string->number(string-append "#b"
(g(h(number->string n 2))))))(if(> m 0)(loop m(add1 c))c))))

Ung dung:

(define (invertBinary s)
  (apply string
         (map
          (λ(x)(if(eq? x #\0)#\1 #\0))
          (string->list s))))

(define (trimLeading0s s)
  (let* ((l (string-length s))
         (k (for/list ((i s)
                       (n l)
                       #:final (not(equal? i #\0)))
              n)))
    (substring s (last k))))

(define (f n)
  (if (= 0 n) 0
      (begin
        (let loop ((n n)
                   (c 1))
          (define m 
            (string->number
             (string-append
              "#b"
              (trimLeading0s
               (invertBinary
                (number->string n 2))))))

          (if (> m 0)
              (loop m (add1 c))
              c)))))

Kiểm tra:

(f 0)
(f 1)
(f 42)
(f 97)
(f 170)
(f 255)
(f 682)
(f 8675309)
(f 4812390)
(f 178956970)
(f 2863311530)

Đầu ra:

0
1
6
3
8
1
10
11
14
28
32

Bạn có thể lưu 2 byte bằng cách thay đổi tlibthành tên 1 byte.
Mego

Làm xong. Cám ơn vì sự gợi ý.
rnso

2

MATL , 7 byte

BY'nwa*

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

Giải trình

          % Implicit input, for example 97
          % STACK: 97
B         % Convert to binary
          % STACK: [1 1 0 0 0 0 1]
 Y'       % Run-length encoding
          % STACK: [1 0 1], [2 4 1]
   n      % Number of elements
          % STACK: [1 0 1], 3
    w     % Swap
          % STACK: 3, [1 0 1]
     a    % Any: gives 1 if any element is nonzero
          % STACK: 3, 1
      *   % Multiply
          % STACK: 3
          % Implicit display

2

Vim, 62 59 byte

-3 byte nhờ DJMcMayhem

C0
<C-r>=pri<Tab>'%b',<C-r>")
<Esc>0qqC<C-r>=tr(@",'01','10')
<Esc>:s/^0\+
k<C-a>j@qq@q

Đây là đầu ra xxd với các ký tự không thể in nguyên vẹn:

0000000: 4330 0d12 3d70 7269 0927 2562 272c 1222  C0..=pri.'%b',."
0000010: 290d 1b30 7171 4312 3d74 7228 4022 2c27  )..0qqC.=tr(@",'
0000020: 3031 272c 2731 3027 290d 1b3a 732f 5e30  01','10')..:s/^0
0000030: 5c2b 0d6b 016a 4071 7140 71              \+.k.j@qq@q

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

Giải trình

C                                   " Delete the number (it goes in @")
0<CR>                               " Print 0 (our counter) and a carriage return
<C-r>=pri<Tab>'%b',<C-r>")<CR><Esc> " Use `printf()` to insert the number as base 2
0qq                                 " Return to column 0, start recording a macro
  C<C-r>=tr(@",'01','10')<CR><Esc>  "   Replace 0s with 1s and vice versa
  :s/^0\+<CR>                       "   Delete leading 0s
  k<C-a>                            "   Increment the number on the line above
  j                                 "   Return to the previous line
  @q                                "   Invoke macro recursively
q@q                                 " Stop recording and invoke macro

1
Đẹp! Một số mẹo: :s/^0*ngắn hơn một byte :s/^0\+và trong khi bạn đang đăng ký "eval", bạn chỉ có thể thực hiện pr<S-tab>'%b',<C-r>")để tự động hoàn tất. (Lưu 4 byte)
DJMcMayhem

Oh, cảm ơn vì mẹo tự động hoàn thành! Tôi không thể sử dụng :s/^0*vì nó khớp với một dòng trống và tôi cần nó thất bại trong việc làm trống một dòng trống để thoát khỏi macro đệ quy.
Jordan

1

Ruby, 26 byte

f=->n{n<1?0:-n%4/2+f[n/2]}

Lấy cảm hứng từ câu trả lời Python của xnor.


0

PHP, 64 byte

dựa trên giải pháp đếm ngược của tôi

for($n=$argv[1];$n;print 1)$n=bindec(strtr(decbin($n),"01",10));

in số lần 1ký tự k, trong đó ksố lần lặp.


+4 byte cho đầu ra số nguyên: (đầu ra trống cho 0)

for($n=$argv[1];$n;$i++)$n=bindec(strtr(decbin($n),"01",10));echo$i;

0

JavaScript (ES6), 44

Hàm đệ quy

Giới hạn ở số nguyên dương javascript, 31 bit:

f=(a,s=0)=>a?f((-1>>>Math.clz32(a))-a,s+1):s

Quản lý số chính xác gấp đôi lên tới 53 bit đáng kể - 59 byte:

F=(a,s=0)=>a?F('0b'+a.toString(2).replace(/./g,1)-a,s+1):s

Theo một cách khác: sử dụng thuật toán tuyệt vời của @Dennis, hàm không đệ quy quản lý tối đa 53 bit, 43 byte:

a=>a&&a.toString(2).match(/(.)\1*/g).length

0

PHP, 51 byte

<?=preg_match_all('/(1+|0+)/',decbin($argv[1])?:o);

Sử dụng biểu thức chính để đếm số lần chạy là 1 hoặc 0. Thật không may, điều này cần một trường hợp đặc biệt cho đầu vào 0yêu cầu thêm 3 byte (và đưa ra thông báo).


a) Sử dụng chữ số> 1 thay vì ođể tránh thông báo. b) Bạn có thể lưu 3 byte bằng -Fcờ và $argnthay vì $argv[1]. c) /1+|0+/nên đủ cho regex.
Tít

0

Java 7, 71 byte

int b(Long a){return a==0?0:1+b(~a&-1L>>>64-a.toString(a,2).length());}

Tôi biết điều này bị đánh bại bởi giải pháp của Geobitssplit (cuối cùng sẽ được đăng) nhưng điều này vẫn rất thú vị để viết


0

Octave, 47 byte

@(x)(sum(dec2bin(bitxor(x,idivide(x,2)))=='1'))

Theo mục OEIS, giá trị mà chúng tôi đang tìm kiếm là giải pháp cho thách thức này cũng bằng với số 1s trong mã Gray cho số nguyên đã cho.

Wikipedia cho tôi biết mã Gray có thể được tính là x ^ (x >> 1), vì vậy trong hàm trên tôi tính mã Gray như vậy, chuyển đổi nó thành một chuỗi nhị phân và đếm xem có bao nhiêu chữ số của chuỗi đó 1.


0

Java 7, 64 byte

long g(Long n){return n.toString(n,2).split("0+").length*2-n%2;}

Tôi biết điều này có thể bị đánh bại bởi một trong những câu trả lời tốt hơn, nhưng tôi đã đưa ra nó trong trò chuyện, và tôi không thể đăng nó sau khi Poke nói điều gì đó về nó :)


0

C, 76 byte

unsigned n,m,i;f(x){for(i=0;x;x^=m-1,i++)for(n=x,m=2;n>>=1;m<<=1);return i;}

Hoạt động cho tất cả các trường hợp thử nghiệm (nhiều như tôi không muốn bao gồm từ không dấu hoặc trường hợp thử nghiệm cuối cùng) ...


0

Bash, 57 byte

Gói: Công dụng cốt lõi, grep, sed, vim (cho xxd)

Giả sử số được đưa ra ở định dạng nhị phân. Độ dài nào cũng được chấp nhận :)

xxd -b -c1|cut -d" " -f2|sed s/^0*//|grep -o .|uniq|wc -l


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.