ความยาวนับถอยหลังแบบไบนารี


18

แรงบันดาลใจจากCount Down จากอินฟินิตี้

กำหนดจำนวนเต็มแบบไม่ลบ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

ลำดับนี้คือA005811ใน OEIS


6
ขั้นตอนที่ 3 นั้นไม่มีประโยชน์ใด ๆ เลย
edc65

@ edc65 ดูเหมือนว่าคุณสามารถทำได้ทั้งขั้นตอนที่ 3 หรือขั้นตอนที่ 4 ขึ้นอยู่กับว่าอัลกอริทึมของคุณถูกจัดวางอย่างไร
Brian J

@ edc65 อาจเป็นเพราะคุณไม่มีประโยชน์ ตัวดำเนินการผกผันแบบง่ายไม่ตัดศูนย์นำหน้าสำหรับคุณ ~(~a) == a
Poke

@Poke Bitwise ไม่ตีความทุกบิตแทน binary รวมทั้งศูนย์ชั้นนำ (และจำนวนเงินที่ไม่มีที่สิ้นสุดของพวกเขาในภาษาที่มีจำนวนเต็มแม่นยำโดยพลการ) สิ่งนี้ไม่เทียบเท่ากับขั้นตอนที่ 2
Dennis

@Poke การดำเนินการผกผันอย่างง่ายแตกต่างจากการใช้ขั้นตอนที่ 1..4 หากคุณต้องการใช้ขั้นตอนเหล่านี้ขั้นตอนที่ 3 นั้นไม่มีประโยชน์เนื่องจากการพลิกในขั้นตอนที่ 2 (ตามที่ปรากฏ) จะไม่เปลี่ยน 0s ที่นำหน้า หากขั้นตอนที่ 2 ไม่เปลี่ยน 0s นำไปสู่การ 1s ชั้นนำแล้ว obviuosly คุณต้องเอาชั้นนำ1sในขั้นตอนที่ 3 ไม่ได้นำ0s
edc65

คำตอบ:


14

เยลลี่ , 6 4 ไบต์

^HBS

ลองออนไลน์! หรือตรวจสอบกรณีทดสอบทั้งหมด

พื้นหลัง

ให้nเป็นจำนวนเต็มที่ไม่เป็นลบ

ขั้นตอนที่ 2 และ 3 ของกระบวนการที่อธิบายไว้ในข้อมูลจำเพาะสามารถระบุได้ว่าเป็นการลบ1นำทั้งหมดและสลับส่วนที่เหลือ

ซึ่งหมายความว่าเราจะเอาตรงกลุ่มหนึ่งที่อยู่ติดกันและเท่าเทียมกันตัวเลขไบนารีในแต่ละซ้ำดังนั้นความยาวไบนารีนับถอยหลังของnเป็นเพียงตัวเลขของกลุ่มเหล่านี้ในฐานเป็นตัวแทนของn สำหรับจุดประสงค์ของการท้าทายนี้ให้คิดว่า0ไม่มีตัวเลข

สำหรับn = 8675309กระบวนการจะมีลักษณะดังต่อไปนี้ในไบนารี

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

แทนที่จะนับกลุ่มเหล่านี้ (ซึ่งอาจล้มเหลวสำหรับ edge case 0 ) เราทำสิ่งต่อไปนี้

nและn: 2มีการแทนเลขฐานสองต่อไปนี้

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

โปรดทราบว่าn: 2 's แทน binary เป็นเพียงn ' s ขยับหนึ่งบิตไปทางซ้าย

ถ้าเรา XOR nและn: 2เราจะได้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

9

Python 2, 30 ไบต์

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

ทดสอบบนIdeone

พื้นหลัง

ให้nเป็นจำนวนเต็มที่ไม่เป็นลบ

ขั้นตอนที่ 2 และ 3 ของกระบวนการที่อธิบายไว้ในข้อมูลจำเพาะสามารถระบุได้ว่าเป็นการลบ1นำทั้งหมดและสลับส่วนที่เหลือ

ซึ่งหมายความว่าเราจะเอาตรงกลุ่มหนึ่งที่อยู่ติดกันและเท่าเทียมกันตัวเลขไบนารีในแต่ละซ้ำดังนั้นความยาวไบนารีนับถอยหลังของnเป็นเพียงตัวเลขของกลุ่มเหล่านี้ในฐานเป็นตัวแทนของn สำหรับจุดประสงค์ของการท้าทายนี้ให้คิดว่า0ไม่มีตัวเลข

สำหรับn = 8675309กระบวนการจะมีลักษณะดังต่อไปนี้ในไบนารี

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

แทนที่จะนับกลุ่มเหล่านี้ (ซึ่งอาจล้มเหลวสำหรับ edge case 0 ) เราทำสิ่งต่อไปนี้

nและn: 2มีการแทนเลขฐานสองต่อไปนี้

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

โปรดทราบว่าn: 2 's แทน binary เป็นเพียงn ' s ขยับหนึ่งบิตไปทางซ้าย

ถ้าเรา XOR nและn: 2เราจะได้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)




3

Java 7112 108 100 90 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/2j/=2สามารถลงไป นอกเหนือจากคำตอบที่ดี!
Kevin Cruijssen

อืม .. พอร์ตจากคำตอบ JavaScript ของ@Neilนั้นสั้นกว่า: int c(int i){return i>0?((i^(i>>=1))%2+c(i):0;}( 47 bytes ) ฉันจะยังคงทิ้งคำตอบปัจจุบันไว้เช่นกันเนื่องจากเป็นแบบดั้งเดิมมากกว่าและพอร์ตจากผู้ใช้รายอื่นเป็นสิ่งที่ตรงกันข้ามกับต้นฉบับ :)
Kevin Cruijssen

3

J, 14 ไบต์

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

นับจำนวนการรันในเลขฐานสองของnด้วยเคสพิเศษที่ส่งคืน 0 สำหรับn = 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

CJam , 11 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 ฉันไม่รู้เลย
Luis Mendo

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

Ungolfed:

(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

คุณสามารถบันทึก 2 ไบต์โดยการเปลี่ยนtlและibชื่อ 1 ไบต์
Mego

เสร็จสิ้น ขอบคุณสำหรับคำแนะนำ
rnso


2

เป็นกลุ่ม62 59 ไบต์

-3 ไบต์ขอบคุณ 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

นี่คือเอาต์พุต 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*สั้นกว่าหนึ่งไบต์:s/^0\+และในขณะที่คุณอยู่ในการลงทะเบียน "eval" คุณสามารถทำการpr<S-tab>'%b',<C-r>")เติมข้อความอัตโนมัติได้ (บันทึก 4 ไบต์)
DJMcMayhem

โอ้ขอบคุณสำหรับเคล็ดลับการเติมข้อความอัตโนมัติ! ฉันใช้ไม่ได้:s/^0*เพราะมันตรงกับบรรทัดว่างเปล่าและฉันต้องการให้มันว่างเปล่าเพื่อให้บรรทัดว่างเปล่าว่างเปล่าเพื่อหลีกเลี่ยงแมโครแบบเรียกซ้ำ
Jordan


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

ใช้ regex เพื่อนับจำนวนการรัน 1 หรือ 0 แต่น่าเสียดายที่ต้องใช้กรณีพิเศษสำหรับอินพุต0ที่ต้องใช้ 3 ไบต์เพิ่มเติม (และแจ้งให้ทราบ)


a) ใช้ตัวเลข> 1 แทนoเพื่อหลีกเลี่ยงการแจ้งให้ทราบล่วงหน้า ข) คุณสามารถบันทึก 3 ไบต์กับ-Fธงและแทน$argn $argv[1]c) /1+|0+/ควรเพียงพอสำหรับ regex
ติตัส


0

ระดับแปดเสียง 47 ไบต์

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

ตามรายการ OEIS ค่าที่เรากำลังมองหาว่าเป็นทางออกสำหรับความท้าทายนี้ก็เท่ากับจำนวนของ1s ในรหัสสีเทาสำหรับจำนวนเต็มที่กำหนด

วิกิพีเดียบอกรหัสสีเทาสามารถคำนวณได้ x ^ (x >> 1) 1ดังนั้นในฟังก์ชั่นดังกล่าวข้างต้นที่ผมคำนวณรหัสสีเทาเป็นเช่นแปลงเป็นสตริงไบนารีและนับจำนวนตัวเลขของสตริงที่มี


0

Java 7, 64 ไบต์

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

ฉันรู้ว่านี้อาจจะแพ้พอร์ตของหนึ่งในคำตอบที่ดี แต่ผมขึ้นมาพร้อมกับมันในการแชทและผมก็ไม่สามารถไม่ได้โพสต์หลังจากที่ทักทายพูดอะไรบางอย่างเกี่ยวกับมัน :)


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 ไบต์

แพ็คเกจ: Core Utililities, grep, sed, vim (สำหรับxxd)

สมมติว่าตัวเลขถูกกำหนดในรูปแบบไบนารี ความยาวใดก็ได้ที่ยอมรับได้ :)

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


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.