二进制倒数长度


18

灵感来自无限计数

给定一个非负整数N,输出达到0所需的以下步骤的重复次数:

  1. 转换N为二进制(4812390 -> 10010010110111001100110
  2. 翻转每一位(10010010110111001100110 -> 01101101001000110011001
  3. 修剪前导零(01101101001000110011001 -> 1101101001000110011001
  4. 转换回十进制(1101101001000110011001 -> 3576217

规则

  • 输入和输出可以采用任何明确,一致的格式
  • 输入将在您的语言的本机可表示整数范围内(如果您的语言支持任意大的整数,则没有限制)

测试用例

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

该序列为OEIS中的A005811


6
第3步完全没有用
edc65 '16

@ edc65好像你可以做任何步骤3或第4步,这取决于你如何算法的布局
布莱恩Ĵ

@ edc65也许对您没有用。一个简单的逆运算符不会为您修剪前导零。~(~a) == a

@Poke按位NOT不会反转二进制表示形式的所有位,包括前导零(以及使用任意精度整数的语言中的无穷多个)。这是不等同于步骤2
丹尼斯

@Poke一个简单的逆运算与应用步骤1..4不同。如果要应用这些步骤,则步骤3没有用,因为步骤2中的翻转(如图所示)不会更改前导0。如果步骤2 确实将前导0更改为前导1,那么您就不得不在步骤3中删除前导1,而不是前导0
edc65 '16

Answers:


14

果冻6 4 字节

^HBS

在线尝试!要么验证所有测试用例

背景

n为非负整数。

可以将规范中描述的过程的第2步和第3步声明为删除所有前导1并切换其余位。

这意味着我们会移除正好一个组的相邻的和等于二进制数在每次迭代中,所以二进制倒计时长度Ñ是这些基团中的二进制表示的只是数量Ñ。出于此挑战的目的,请将0视为没有数字。

对于n = 8675309,该过程以二进制形式显示如下。

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

而不是对这些组进行计数(对于边缘情况0,这将失败),我们执行以下操作。

nn:2具有以下二进制表示形式。

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

注意,n:2的二进制表示形式就是n,向左移动一位。

如果我们对nn:2进行 XOR运算,则将获得1(MSB),并且每对不同的相邻数字将获得一个额外的1。因此,组的数量等于n⊻n:2中的设置位数。

怎么运行的

^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
惊人!完全不同的推理
edc65 '16

9

Python 2,30个字节

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

Ideone上进行测试

背景

n为非负整数。

可以将规范中描述的过程的第2步和第3步声明为删除所有前导1并切换其余位。

这意味着我们会移除正好一个组中的每个迭代中相邻且平等的二进制数字,所以二进制倒计时长度Ñ只是在的二进制表示这些基团的数目Ñ。出于此挑战的目的,请将0视为没有数字。

对于n = 8675309,该过程以二进制形式显示如下。

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

而不是计算这些组(对于边缘情况0会失败,),我们执行以下操作。

nn:2具有以下二进制表示形式。

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

注意,n:2的二进制表示形式就是n,向左移动一位。

如果我们对nn:2进行 XOR运算,则将获得1(MSB),并且每对不同的相邻数字将获得一个额外的1。因此,组的数量等于n⊻n:2中的设置位数。


9

Python 2,29个字节

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

计算二进制扩展中0到1之间的交替数,将前导1视为交替。这样做是通过检查最后两个二进制数字是否不同,然后递归到删除了最后一个数字的数字上来。如果n%4是1或2,则后两位数字完全不同,可以将其检查为-n%4/2


6

JavaScript(ES6),26个字节

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

通过计算0到1之间的转换来工作。最多只能使用31位。29个字节以支持53位:

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

5

Haskell,34个字节

b 0=0
b n|x<-b$div n 2=x+mod(x+n)2

我喜欢它怎么说“ 0 = 0” :)
AlexR

4

05AB1E7 5字节

感谢Dennis节省了2个字节。

b0ÛÔg

如果没有边缘情况0,则可能为3个字节bÔg

在线尝试!或作为测试套件

说明

b      # convert to binary
 0Û    # trim off leading zeroes
   Ô   # remove adjacent duplicates
    g  # length

3

CJam,14个字节

ri0{2b:!2bj)}j

在线尝试!

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

基本上是我回答其他问题的答案


3

Java 711210810090 73个字节

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

基本思路

 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/2可以缩短为j/=2。除了一个很好的答案!
凯文·克鲁伊森

嗯..从端口@Neil的JavaScript的答案是短虽然:int c(int i){return i>0?((i^(i>>=1))%2+c(i):0;}47个字节)。不过,我仍然会留下您当前的答案,因为它是更原始的,来自其他用户的端口与原始端口完全相反。:)
Kevin Cruijssen '16

3

J,14个字节

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

计算n的二进制数字中的运行次数,特殊情况下对于n = 0 返回0。

用法

   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

说明

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

CJam11个10字节

感谢@Dennis节省了一个字节!

ri_2be`,e&

在线尝试!

说明

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&(逻辑与)保存一个字节\g*
丹尼斯

@丹尼斯谢谢!CJam的逻辑AND的工作方式很方便,我不知道
Luis

2

球拍349字节

(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))))

取消高尔夫:

(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)))))

测试:

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

输出:

0
1
6
3
8
1
10
11
14
28
32

您可以通过将tl和更改ib为1个字节的名称来保存2个字节。
Mego

做完了 谢谢你的建议。
rnso

2

MATL,7个字节

BY'nwa*

在线尝试!

说明

          % 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字节

-DJMcMayhem -3个字节

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

这是带有不可打印字符的xxd输出:

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

在线尝试!

说明

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
真好!一些提示::s/^0*比短1个字节:s/^0\+,并且当您处于“ eval”寄存器中时,您可以pr<S-tab>'%b',<C-r>")进行自动完成。(保存4个字节)
DJMcMayhem

哦,谢谢你的自动完成提示!我不能使用:s/^0*它,因为它匹配一个空行,并且我需要它失败以使一个空行逃脱递归宏。
约旦

1

Ruby,26个字节

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

受到xnor的Python答案的启发。


0

PHP,64字节

根据我的倒计时解决方案

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

打印1字符k时间,其中k为迭代次数。


+4个字节用于整数输出:(用于的空输出0

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

0

JavaScript(ES6),44

递归函数

限于javascript正整数,31位:

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

管理双精度数,最多53个有效位-59字节:

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

换句话说,使用@Dennis的惊人算法,非递归函数可管理53位,43字节:

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

0

PHP,51字节

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

使用一个正则表达式计算1或0的运行次数。不幸的是,这需要特殊的情况进行输入,0该输入需要3个额外的字节(并给出一个通知)。


a)使用数字> 1代替o以避免引起注意。b)您可以使用-F标志而$argn不是保存3个字节$argv[1]。c)/1+|0+/应该足以满足正则表达式。
泰特斯

0

Java 7,71个字节

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

我知道这被Geobits的split解决方案击败了(最终将被发布),但是写起来还是很有趣的


0

八度,47字节

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

根据OEIS条目,我们正在寻找作为解决此难题的方法的值等于给1定整数格雷码中的s数。

Wikipedia告诉我,格雷码可以计算为x ^(x >> 1),因此在上面的函数中,我这样计算格雷码,将其转换为二进制字符串,并计算该字符串的位数1


0

Java 7,64个字节

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

我知道这可能会被一个更好的答案之一打败,但是我在聊天中想到了它,在Poke说了些关于它的事情之后,我无法将其发布:)


0

C,76字节

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

适用于所有测试用例(就我不想包括无符号或最后一个测试用例一词而言)...


0

Bash,57个字节

软件包:核心实用工具,grep,sed,vim(用于xxd

假设数字以二进制格式给出。任何长度都可以接受:)

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


0

Tcl,119字节

proc D n i\ 0 {
while \$n {set n [regsub ^0+(?=.) [string map {0 1 1 0} [format %b $n]] ""]
incr i
scan $n %b n}
set i}

在线尝试!

就我的口味而言仍然很不满意

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.