Dureza Digital de Inteiros

26

Para encontrar a dureza digital de um número inteiro, obtenha sua representação binária e conte o número de vezes que uma guia inicial e uma final 1podem ser removidas até que iniciem ou terminem com a 0. O número total de bits removidos é a sua dureza digital.

Essa é uma explicação bastante prolixo - então vamos detalhar com um exemplo bem trabalhado.

Neste exemplo, usaremos o número 3167. Em binário, é o seguinte:

110001011111

(Observe que, durante a conversão para binário, retire os zeros iniciais)

Como não começa nem termina 0, removemos 1 par de bits:

1  1000101111  1

E outro:

11  00010111  11

Mas agora há um 0 no começo, então não podemos remover mais 1pares. No total, removemos 4 bits e, portanto, 4 é a dureza digital de 3167.

No entanto, para números que podem ser escritos como 2 n -1 para n positivo (ou seja, contêm apenas 1na representação binária), 0 nunca será alcançado e, portanto, todos os bits poderão ser removidos. Isso significa que a dureza é simplesmente o tamanho do bit do número inteiro.


O desafio

n >= 0Sua tarefa é escrever um programa ou função que, dado um número inteiro não negativo , determine sua dureza digital.

Você pode enviar um programa completo que execute E / S ou uma função que retorne o resultado. Seu envio deve funcionar com valores ndentro do intervalo inteiro padrão do seu idioma.


Casos de teste

Notifique-me se algum deles estiver incorreto ou se você gostaria de sugerir algum caso extremo a ser adicionado.

0     -> 0
1     -> 1
8     -> 0
23    -> 2
31    -> 5
103   -> 4
127   -> 7
1877  -> 2
2015  -> 10

Aqui está a solução Python não utilizada que eu usei para gerar esses casos de teste (não é garantido que não haja erros):

def hardness(num) -> int:
    binary = bin(num)[2:]

    if binary.count('0') == 0:
        return num.bit_length()

    revbin = binary[::-1]

    return min(revbin.find('0'), binary.find('0')) * 2
FlipTack
fonte
1
Como 1retorna 1 quando não há nenhum 0? Quero dizer, você não pode remover 1s suficientes da string para que ela comece ou termine 0.
busukxuan
2
@busukxuan Leia o parágrafo imediatamente antes do cabeçalho "The Challenge": para números que podem ser escritos como 2 ^ n-1 (ou seja, contêm apenas 1 na representação binária), 0 nunca será alcançado e, portanto, todos os bits poderão ser removidos . Isso significa que a dureza é simplesmente o tamanho do bit do número inteiro.
FlipTack
2
@busukxuan, você pode pensar nisso como o número de unidades de cada lado, antes que os zeros sejam atingidos.
FlipTack 6/01
2
Para o downvoter que obviamente não gostou dos casos extremos: A dureza é o número de (1) bits sólidos com os quais é preenchida - se tudo é sólido, então certamente tem 100% de dureza, todo o comprimento de bit?
FlipTack 6/01
1
@FlipTack Eu não quero influenciar muito, é o seu desafio. Inicialmente, entendi "dureza" como o número máximo de pares de pares externos que podem ser removidos, um de cada lado. Mas você pode estar certo, se uma única pessoa permanece no final, talvez ele deve ser contado em
Luis Mendo

Respostas:

6

Geléia , 11 10 bytes

BµQL××Ṛa\S

Experimente online!

Como funciona

BµQL××Ṛa\S  Main link. Argument: n

B           Binary; convert n to base 2.
 µ          Begin a new, monadic chain. Argument: A (array of binary digits)
  Q         Unique; deduplicate the digits.
   L        Length; count the unique digits.
    ×       Multiply each digit by the result.
     ×Ṛ     Multiply the results by reversed A.
       a\   Cumulative reduce by logical AND.
            This zeroes out all elements after the first zero.
         S  Compute the sum of the result.
Dennis
fonte
8

Python , 76 69 68 63 62 60 57 bytes

f=lambda n,k=0:n>>k&(n&n>>k>n>>k+1)and(n&n+1>0)-~f(n,k+1)

Experimente online!

Como funciona

Esta é uma solução recursiva que recebe uma entrada n e continua aumentando k - começando em 0 - enquanto LSB k (n) (bit no índice k da direita) e MSB k (n) (bit no índice k da esquerda) estão prontos. Uma vez finalizado, ele retorna k se todos os bits de n estiverem definidos e 2k, se não.

Vamos começar reescrevendo o lambda f como uma função nomeada F , com uma variável auxiliar t .

def F(n, k = 0):
    t = n >> k
    return t & (n & t > t >> 1) and (n & (n + 1) > 0) + 1 + F(n, k + 1)

Em cada chamada de F , que primeiro bit de deslocamento n um total de K unidades para a direita e armazenar o resultado em t . Dessa forma, LSB 0 (t) = LSB k (n) , então t é ímpar se e somente se LSB k (n) estiver definido.

Determinar se MSB k (n) está definido é um pouco mais complicado; é isso que n & t > t >> 1alcança. Para ilustrar como funciona, vamos considerar um número inteiro n = 1αβγδεζη 2 de comprimento 8 e analisar a chamada de função F (n, 3) , ou seja, k = 3 .

Estamos tentando determinar se o MSB 3 (n) = γ é definido examinando o valor de verdade da comparação (n & t> t >> 1) = (1αβγδεζη 2 & 1αβγδ 2 > 1αβγ 2 ) . Vamos examinar os números inteiros envolvidos.

MSB-index  012k4567

n          1αβγδεζη
t             1αβγδ

t >> 1         1αβγ

Afirmamos que γ = 1 se e somente se n & t> t >> 1 .

  • Se γ = 1 , então n & t possui bit 5, enquanto t >> 1 possui bit 4 , então n & t> t >> 1 .

    Isso prova que γ = 1 implica n & t> t >> 1 .

  • Se n & t> t >> 1 , há duas opções: γ = 1 ou γ = 0 . No primeiro caso, não há mais nada a provar.

    No segundo caso, temos que αβγδ 2 ≥ n & t> t >> 1 = 1αβγ 2 .

    Como αβγδ 2 > 1αβγ 2 , devemos ter MSB 0 (αβγδ 2 ) ≥ MSB 0 (1αβγ 2 ) , significando que α = 1 .

    Dessa forma, 1βγδ 2 > 11βγ 2 , portanto, devemos ter o MSB 1 (1βγδ 2 ) ≥ MSB 1 (11βγ 2 ) , o que significa que β = 1 .

    Por sua vez, isso implica que 11γδ 2 > 111γ 2 . Lembrando que γ = 0 no segundo caso, obtemos a desigualdade 110δ 2 > 1110 2 , o que é falso desde MSB 2 (110δ 2 ) = 0 <1 = MSB 2 (1110 2 ) .

    Assim, apenas o primeiro caso é possível e n & t> t >> 1 implica γ = 1 .

Resumindo, se LSB k (n) e MSB k (n) estiverem definidos, t será ímpar e n & t> t >> 1 será True , portanto t & (n & t> t >> 1) será rendimento 1 . No entanto, se LSB k (n) ou MSB k (n) estiver desativado (ou se ambos estiverem), t será par ou n & t> t >> 1 será False , então t & (n & t> t> > 1) produzirá 0 .

Chamar F com um único argumento inicializa k = 0 . Embora a condição que discutimos anteriormente seja válida, o código apósand é executado, que (entre outras coisas) chama recursivamente F com k incrementado .

Uma vez que LSB k (n) ou MSB k (n) não está definido, a condição falha e F (n, k) retorna 0 . Cada uma das chamadas de função k anteriores adiciona (n & (n + 1)> 0) + 1 a F (n, k) = 0 , portanto F (n) retorna ((n & (n + 1)> 0) + 1) k .

Agora, se todos os bits de n forem iguais (ou seja, se n for 0 ou se todos os seus bits estiverem configurados), n + 1 não terá nenhum bit em comum com n , então n & (n + 1) = 0 e F (n) retorna k . No entanto, se n tiver bits definidos e não definidos, n & (n + 1)> 0 e F (n) retornarão 2k .

Dennis
fonte
2
As soluções recursivas em Python parecem estar se saindo muito bem ultimamente.
mbomb007
Pelo menos em comparação com soluções iterativas, elas sempre o têm. input(), whileE printjá são 17 bytes ...
Dennis
Sim, mas acho-os muito mais difíceis de escrever.
mbomb007
1
Justo. Uma implementação iterativa direta da mesma ideia seria apenas 5 bytes mais longa. tio.run/nexus/… Mais 2 bytes podem ser salvos com alguns truques. tio.run/nexus/python2#JY1BDsIgFAXX7SnepgUUI1BNm1K4jKVJQ/...
Dennis
6

MATL , 13 12 bytes

Btv`6L&)}x@q

Experimente online! Ou verifique todos os casos de teste .

Explicação

O código repete cada dígito binário e conta quantas vezes é possível remover dois dígitos externos.

B        % Input number (implicit). Horizontal vector of binary digits
tv       % Duplicate and concatenate vertically
`        % Do...while
  6L&)   %   Flatten the array if needed (in column-major order), and split it
         %   into two subarrays: one with the inner entries, and another
         %   with the two outer entries. The latter will be used for deciding
         %   if the loop continues or is exited
}        % Finally (execute before exiting the loop)
  x      %   Delete last subarray of inner entries
  @q     %   Push last iteration index minus 1
         % End (implicit). The next iterarion is executed if the array at the
         % top of the stack is non-empty and only contains nonzero values. 
         % Otherwise the loop is exited, executing the "finally" block first
         % Display (implicit)
Luis Mendo
fonte
6

Python, 82 bytes

Sinto que ainda pode jogar golfe, mas passei um tempo tentando métodos diferentes e esse foi o mais curto.

def f(n):b=bin(n)[2:];x=min(b.find('0'),b[::-1].find('0'));print(x<0)*len(b)or x*2

Experimente online

Embora isso funcione de maneira semelhante ao programa Python do OP, eu o criei antes que a pergunta fosse publicada, depois de visualizá-la na Sandbox, que não continha esse programa.

mbomb007
fonte
6

Python 2, 66 bytes

s=bin(input())[2:].split('0')
print len(min(s[-1],s[0]))<<1%len(s)

Divide a representação binária da entrada em partes de 1. Conta o número de 1's no menor e no primeiro e último pedaço e depois dobra-o, a menos que haja um único pedaço que isso contaria duas vezes.

xnor
fonte
Inteligente, mas ainda fácil de entender. Eu gosto disso!
mbomb007
5
@ mbomb007 Tomá-lo como um warm up para a compreensão de Dennis :)
xnor
3

PowerShell , 109 106 bytes

$a=[convert]::ToString($args[0],2)-split0;(((($b=$a[0].length),$a[-1].length|sort)[0]*2),$b)[$a.count-eq1]

Experimente online!

Recebe entrada $args[0], usa a chamada .NET para convertela toStringcom base 2(ou seja, torna-a binária), depois -splits que string em 0s, armazena-o em $a. Importante observar: a chamada do .NET não retorna zeros à esquerda, portanto, o primeiro dígito é sempre um1 .

Existem, portanto, duas possibilidades - a string binária é todas, ou havia pelo menos um zero. Diferenciamos aqueles com pseudo-ternário indexado por $a.count-eq1. Se o binário tiver pelo menos um zero, o caso esquerdo, usaremos o mínimo do comprimento da primeira [0]string de se 1da última [-1]string (encontrada por |sorte então [0]). O menor desses é o maior número de pares que podemos remover, portanto multiplicamos por 2. Observe que, se a string binária original terminar em a 0, como na entrada 8, [-1].lengthtambém será 0(já que é uma string vazia), que quando multiplicada por 2ainda é 0.

Caso contrário, com todas as cadeias binárias, consideraremos justamente $b(que anteriormente era definido como o comprimento da primeira [0]cadeia, nesse caso, a totalidade da cadeia binária).

Em qualquer das situações, esse resultado é deixado no pipeline e a saída é implícita.

AdmBorkBork
fonte
3

JavaScript (ES6), 57 bytes

f=
n=>n.toString(2).replace(/^(1*)(.*(\1))?$/,'$1$3').length
<input oninput=o.value=1/this.value?f(+this.value):''><input id=o readonly>

Pega o binário e tenta corresponder a todos 1sou com falha nesse número igual de inicial e final 1s.

Neil
fonte
2

Retina , 48 bytes

.+
$*
+`(1+)\1
$1o
o1
1
m(+`^1(.*)1$
xx¶$1
x|^1$

Experimente online

Explicação:

.+              # Convert to unary
$*
+`(1+)\1        # Convert to binary (but with `o` instead of `0` -- it's shorter)
$1o
o1
1
m(+`^1(.*)1$    # Replace pairs of surrounding ones with `xx`
xx¶$1
x|^1$,          # Count x's, including the possibility of a single remaining `1`
mbomb007
fonte
2

C #, 133 bytes

Função que retorna dureza. Pega inteiro do argumento.

int h(int b){var n=Convert.ToString(b,2);for(b=0;;){if(n[0]+n[n.Length-1]==98)n=n.Substring(1,n.Length-2);else break;b+=2;}return b;}

Bem, hoje eu descobri '1' + '1' = 98em C #.

devRicher
fonte
1
Isso porque '1'é o caractere ASCII 49, e 49 + 49 = 98.
FlipTack
Eu literalmente passei 10 minutos descobrindo por que o meu 1 + 1 = 2não funcionou. @FlipTack
devRicher
2

C, 89 88 85 bytes

Dois bytes salvos devido a @FlipTack apontar uma declaração inútil.

Ligue f()com o número para testar, a saída é retornada da função.

t,h;f(l){for(t=l;t&&~t&1<<30;t*=2);for(h=0;t&1<<30&&l&1;t*=2,l/=2)++h;return h<<!!l;}

Experimente em ideone .

owacoder
fonte
2

JavaScript (ES6), 59 58 bytes

f=(n,m=1<<30)=>m>n?f(n,m/2):m>1?n&m&&n&1&&2+f(n/2,m/4):n&1

Casos de teste

Arnauld
fonte
2

C, 137 132 122 119 117 114 98 94 92 87 85 Bytes

Hora de começar a jogar golfe B-)

i,j;f(n){for(i=1<<30;i&~n;i/=2);for(j=0;n&i;n/=2,i/=4)j+=~n&1?i=0:2;return j-=n<1*j;}

Aqui está a prova

main()
{
  printf("%d %d\n", 0, f(0));
  printf("%d %d\n", 1, f(1));
  printf("%d %d\n", 8, f(8));
  printf("%d %d\n", 23, f(23));
  printf("%d %d\n", 31, f(31));
  printf("%d %d\n", 103, f(103));
  printf("%d %d\n", 127, f(127));
  printf("%d %d\n", 1877, f(1877));
  printf("%d %d\n", 2015, f(2015));
  printf("%d %d\n", 3167, f(3167));
} 

e a saída;

0 0
1 1
8 0
23 2
31 5
103 4
127 7
1877 2
2015 10
3167 4 
cleblanc
fonte
1

Java (OpenJDK) , 181 156 150 bytes

n->{int i=0;String s=n.toString(n,2);if(s.matches("1*"))i=s.length();else for(;!s.matches("(.*0)|(0.*)");s=s.substring(1,s.length()-1))i+=2;return i;}

Experimente online!

Pavel
fonte
1

Mathematica, 63 56 bytes

(2-Min[l=#~IntegerDigits~2])Min[Tr/@Split[l][[{1,-1}]]]&

Explicação

l=#~IntegerDigits~2

Gere a representação base-2 da entrada, envolvida por um List . Armazene isso eml

(2-Min[...])

Se o elemento min de l for 1, saída 1. Caso contrário, saída 2. Multiplique isso por ...

Split[l]

Dividido l em execuções.

... [[{1,-1}]]

Pegue o primeiro e o último elemento.

Tr/@ ...

Pegue o total de ambos.

Min[ ... ]

Encontre o menor entre os dois.

(Multiplique o primeiro resultado (1 ou 2) com este resultado).

JungHwan Min
fonte
1

Oitava, 56 54 bytes

 @(n)cummin(d=dec2bin(n)-48)*cummin(flip(d))'*2^!all(d)

Experimente Online!

Explicação:

d=dec2bin(n)-48

representação binária de n

cumd= cummin(d);
cumfd = cummin(flip(d));

Tome min acumulado de d e min acumulado de viradod

res = cumd * cumfd ';

faça multiplicação de matrizes

out = res*2^!all(d)

multiplique por 2 se todos os dígitos forem 1;

rahnema1
fonte
@FlipTack Obrigado, link atualizado!
precisa saber é o seguinte
1

Pitão, 18 bytes

?*FJjQ2lJyhSxR0_BJ

Um programa que recebe a entrada de um número inteiro e imprime o resultado.

Suíte de teste (primeira linha para formatação)

Como funciona

?*FJjQ2lJyhSxR0_BJ  Program. Input: Q
?                   If
  F                 reducing
    jQ2             the binary representation of Q as a list
   J                (store in J)
 *                  by multiplication is truthy:
       lJ            Yield len(J)
                    Else:
          hS         Yield the minimum
            xR0      of the first index of zero
               _BJ   in J and its reverse
         y           * 2
                    Implicitly print
TheBikingViking
fonte
1

APL, 26 bytes

+/∘(∧\≢↑(∊⊢(,∧∧)¨⌽))2⊥⍣¯1⊢

Casos de teste:

      ( +/∘(∧\≢↑(∊⊢(,∧∧)¨⌽))2⊥⍣¯1⊢ ) ¨ 0 1 8 23 31 103 127 1877 2015    
0 1 0 2 5 4 7 2 10

Explicação:

+ / ∘ (∧ \ ≢ ↑ (∊⊢ (, ∧∧) ¨⌽)) 2⊥⍣¯1⊢

                         ⊢ entrada
                    2⊥⍣¯1 converte em representação binária
   ()
        (⊢ ¨⌽) para cada bit e seu bit correspondente do outro lado
            (∧) pegue o lógico e de ambos os bits,
             , faça uma lista dos dois bits,
              Take então pegue oe da lista e oe
         ∊ achatar a matriz resultante
      Take pegue apenas os primeiros N bits, onde N é o
                                comprimento da lista original de bits
    \ Tome uma lógica de execução e (deixando apenas o
                                começando)
+ / ∘ soma aqueles
marinus
fonte
1

J, 22 bytes

(#<.2*(<.&(#.~)|.))@#:

Isso se baseia no puro truque aprendido com esse desafio .

Experimente online!

Explicação

(#<.2*(<.&(#.~)|.))@#:  Input: integer n
                    #:  Binary digits of n
(                 )@    Operate on those digits D
               |.         Reverse D
       <.                 Take the minimum of
         &(#.~)           the "trailing truths" of D and reverse(D)
    2*                    Multiply by 2
 #                        The length of D
  <.                      Minimum of length and the previous result
milhas
fonte
1

PHP, 83 74 bytes

3 + 6 bytes salvos por Jörg

<?=(~$s=decbin($argn))[$a=strspn($s,1)]?min($a,strspn(strrev($s),1))*2:$a;

recebe entrada do STDIN; corra com -nR.

demolir

<?=                     # print ...
(~
    $s=decbin($argn)        # $s = binary representation of input
)[
    $a=strspn($s,1)         # $a = number of leading `1`s
]                           # if $s has more than $a digits,
?   min($a,                     # 2. minimum of $a and
        strspn(strrev($s),1)    # 1. number of trailing `1`s
    )*2                         # 3. *2
:   $a                      # else $a (==strlen)
Titus
fonte
1
<?=~($s=decbin($argn))[$a=strspn($s,1)]?2*min($a,strspn(strrev($s),1)):$a;
Jörg Hülsermann
0

JavaScript (ES6), 83 bytes

f=x=>(y=x.toString(2),y.match(/^1*$/)?y:([s,e]=y.match(/^1*|1*$/g),s<e?s:e)).length

Ungolfed:

function f(n) {
    var binStr = n.toString(2);
    if(binStr.match(/^1*$/)) {
        // If binary representation is all 1s, return length of binary
        return binStr.length;
    } else {
        // Grab the starting and ending 1s in the binary representation
        var [start1s, end1s] = binStr.match(/^1*|1*$/g);
        var startHardness = start1s.length;
        var endHardness = end1s.length;
        return Math.min(startHardness, endHardness);
    }
}
Joshua David
fonte
0

Mathematica, 62 bytes

(h=0;#~IntegerDigits~2//.{{1,m___,1}:>(h+=2;{m}),{1}:>h++};h)&

Função pura onde #representa o primeiro argumento.

(h=0;...;h)&define h=0, faz um monte de coisas ..., depois retorna h(a dureza). Vejamos o monte de coisas:

#~IntegerDigits~2                                     Binary representation of the input
                 //.                                  Apply the following list of rules repeatedly until there is no change
                    {                                 Start of the list of rules
                     {1,m___,1}                       If you see a list starting and ending with 1 with the sequence m (possibly empty) in between
                               :>(h+=2;{m}),            replace it with just {m} after incrementing h twice.
                                            {1}       If you see the singleton list {1}
                                               :>h++    replace it with h, then increment h.
                                                    } End of the list of rules

Agradeço a Greg Martin por me apresentar esse truque .

ngenisis
fonte
0

Haskell , 94 92 bytes

b 0=[]
b n=mod n 2:b(div n 2)
h n|(c,_:_)<-span(>0)$zipWith(*)n$reverse n=c++c|1<3=n
sum.h.b

Experimente online! Uso:

Prelude> sum.h.b $ 3167
4

Explicação:
b converte um número em binário e retorna uma lista de zero e aqueles com o bit menos significativo primeiro. Em h, essa lista é revertida e multiplicada por elementos com a lista original, depois é span(>0)dividida após os 1s iniciais :

       b 3167 = [1,1,1,1,1,0,1,0,0,0,1,1] = n
    reverse n = [1,1,0,0,0,1,0,1,1,1,1,1] = m
zipWith(*)n m = [1,1,0,0,0,0,0,0,0,0,1,1] = z
   span(>0) z = ([1,1],[0,0,0,0,0,0,0,0,1,1])

A tupla resultante é correspondida com o padrão (c,_:_)onde _:_corresponde a qualquer lista não vazia, portanto c = [1,1]. Como os bytes são removidos na frente e atrás, c++c = [1,1,1,1]são retornados e finalmente somados para produzir a dureza digital .

Se a segunda lista da tupla estiver vazia, a representação binária conterá apenas uma, e o número de unidades é a dureza digital. Com a correspondência de padrões, o hretorno falha apenas n, que é novamente resumido.

Laikoni
fonte
0

Perl, 61 bytes

sub f{$_=sprintf('%b',pop);length(/0/?/^(1+).*\1$/&&$1x2:$_)}

O coração disso é a expressão regular, /^(1+).*\1$/onde 2 vezes o comprimento de $1é a resposta. O restante do código está sobrecarregado e trata do caso especial de todos os 1.

cdlane
fonte
Você pode omitir os parênteses em torno dos sprintfargumentos. Além disso, o uso do -psinalizador permitirá que você escreva um programa completo que seja mais curto do que sua função, como você poderá omitir sub f{...}(em vez disso, você terá que terminar, $_=...mas isso ainda é uma melhoria de 4 bytes). Finalmente, em vez de length(...)você, você pode fazer /0/&&s/^(1+).*\1$/$1$1/;$_=y///c. Isso deve levar a 51 bytes.
Dada
0

PHP, 65 bytes

<?=strlen(preg_filter('#^(1*)(.*(\1))?$#',"$1$3",decbin($argn)));

Versão Online

Jörg Hülsermann
fonte
0

CJam, 14 bytes

ri2b_0#\W%0#e<

Explicação:

ri e# Read integer:      | 3167
2b e# Convert to binary: | [1 1 0 0 0 1 0 1 1 1 1 1]
_  e# Duplicate:         | [1 1 0 0 0 1 0 1 1 1 1 1] [1 1 0 0 0 1 0 1 1 1 1 1]
0# e# Index of first 0:  | [1 1 0 0 0 1 0 1 1 1 1 1] 2
\  e# Swap:              | 2 [1 1 0 0 0 1 0 1 1 1 1 1]
W% e# Reverse:           | 2 [1 1 1 1 1 0 1 0 0 0 1 1]
0# e# Index of first 0:  | 2 5
e< e# Minimum:           | 2
Esolanging Fruit
fonte