Двоичная длительность обратного отсчета


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

Эта последовательность A005811 в OEIS.


6
Шаг 3 вообще бесполезен
edc65

@ edc65 Похоже, что вы можете выполнить либо шаг 3, либо шаг 4, в зависимости от того, как устроен ваш алгоритм
Брайан Дж

@ edc65 Может быть, для вас это бесполезно. Простой обратный оператор не обрезает начальные нули для вас. ~(~a) == a
Ткните

@Poke Bitwise NOT инвертирует все биты двоичного представления, включая начальные нули (и их бесконечное количество в языках с произвольными целыми числами точности). Это не эквивалентно шагу 2.
Деннис

@Poke Простая обратная операция отличается от применения шагов 1..4. Если вы хотите применить эти шаги, шаг 3 бесполезен, потому что переворот на шаге 2 (как показано) не меняет начальные 0. Если шаг 2 действительно меняет ведущие 0 на ведущие 1, то, очевидно, вы должны удалить ведущие 1 на шаге 3, а не ведущие 0
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

Вместо того, чтобы считать эти группы (что не получится для граничного случая 0 ), мы делаем следующее.

n и n: 2 имеют следующие двоичные представления.

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

Обратите внимание, что двоичное представление n: 2 - это просто n , сдвинутое на один бит влево.

Если мы 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

Вместо того, чтобы считать эти группы (что не получится для граничного случая 0 ), мы делаем следующее.

n и n: 2 имеют следующие двоичные представления.

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

Обратите внимание, что двоичное представление n: 2 - это просто n , сдвинутое на один бит влево.

Если мы 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)

5

Haskell, 34 байта

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

Мне нравится, как это говорит "0 = 0" :)
AlexR


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 7,112 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/2можно сократить до j/=2. Помимо этого отличный ответ!
Кевин Круйссен

Хм ... порт из ответа @Neil в JavaScript короче: int c(int i){return i>0?((i^(i>>=1))%2+c(i):0;}( 47 байт ). Я бы все же оставил ваш текущий ответ, так как он более оригинальный, а порты других пользователей - полная противоположность оригиналу. :)
Кевин Круйссен

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, я понятия не имел
Луис Мендо

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и ib1-байтовые имена.
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 байт

-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*потому что он соответствует пустой строке, и мне нужно, чтобы он потерпел неудачу из-за пустой пустой строки, чтобы избежать рекурсивного макроса.
Иордания

1

Рубин, 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 дополнительных байта (и выдает уведомление).


а) Используйте цифру> 1 вместо того, oчтобы избежать уведомления. б) Вы можете сохранить 3 байта с -Fфлагом и $argnвместо $argv[1]. в) /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, ценность, которую мы ищем как решение этой проблемы, также равно числу 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;}

Работает для всех тестовых случаев (насколько я не хочу включать слово unsigned или последний тестовый случай) ...


0

Баш, 57 байт

Пакеты: Основные утилиты, grep, sed, vim (для xxd )

Предположим, что номер указан в двоичном формате. Любая длина приемлема :)

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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.