Durezza digitale di numeri interi


26

Per trovare la durezza digitale di un numero intero, prendere la sua rappresentazione binaria, e contare il numero di volte sia un leader e posteriore 1può essere rimosso fino a quando non sia avviato o termina con 0. Il numero totale di bit rimossi è la sua durezza digitale.

Questa è una spiegazione piuttosto prolissa, quindi analizziamola con un esempio funzionante.

Per questo esempio, useremo il numero 3167. In binario, questo è:

110001011111

(Si noti che, durante la conversione in binario, è necessario assicurarsi di eliminare gli zero iniziali)

Non inizia o termina con 0, quindi rimuoviamo 1 coppia di bit:

1  1000101111  1

E un altro:

11  00010111  11

Ma ora c'è uno 0 all'inizio, quindi non possiamo rimuovere più 1coppie. In totale, abbiamo rimosso 4 bit, quindi 4 è la durezza digitale di 3167.

Tuttavia, per i numeri che possono essere scritti come 2 n -1 per n positivo (cioè contengono solo 1in rappresentazione binaria), non verrà mai raggiunto 0 e quindi tutti i bit possono essere rimossi. Ciò significa che la durezza è semplicemente la lunghezza in bit dell'intero.


La sfida

Il tuo compito è quello di scrivere un programma o una funzione che, dato un numero intero non negativo n >= 0, determina la sua durezza digitale.

È possibile inviare un programma completo che esegue I / O o una funzione che restituisce il risultato. Il tuo invio dovrebbe funzionare per valori ncompresi nell'intervallo intero standard della tua lingua.


Casi test

Si prega di avvisare se qualcuno di questi è errato o se si desidera suggerire eventuali casi limite da aggiungere.

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

Ecco la soluzione ungolfed di Python che ho usato per generare questi casi di test (non garantito che sia privo di bug):

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

1
Come 1restituisce 1 quando non ce n'è in alcun 0modo? Voglio dire, non è possibile rimuovere abbastanza 1 dalla stringa per farla iniziare o finire 0.
Busukxuan,

2
@busukxuan Leggi il paragrafo appena prima dell'intestazione "La Sfida": per i numeri che possono essere scritti come 2 ^ n-1 (cioè contengono solo 1 in rappresentazione binaria), non verrà mai raggiunto 0 e quindi tutti i bit possono essere rimossi . Ciò significa che la durezza è semplicemente la lunghezza in bit dell'intero.
FlipTack

2
@busukxuan puoi immaginarlo come il numero di quelli che ogni lato è imbottito, prima che vengano raggiunti gli zero.
FlipTack

2
Per il downvoter che ovviamente non ha gradito i casi limite: la durezza è il numero di bit solidi (1) con cui è imbottito - se il tutto è solido, allora sicuramente ha una durezza del 100%, la sua intera lunghezza di bit?
FlipTack

1
@FlipTack Non voglio influenzare troppo, è la tua sfida. Inizialmente ho capito "durezza" come il numero massimo di coppie di quelle esterne che possono essere rimosse, una per parte. Ma potresti avere ragione, se alla fine ne rimane uno solo, forse dovrebbe essere contato
Luis Mendo,

Risposte:


6

Gelatina , 11 10 byte

BµQL××Ṛa\S

Provalo online!

Come funziona

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.

8

Python , 76 69 68 63 62 60 57 byte

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

Provalo online!

Come funziona

Questa è una soluzione ricorsiva che accetta un input n e continua ad aumentare k - a partire da 0 - mentre sia LSB k (n) (bit all'indice k da destra) che MSB k (n) (bit all'indice k da sinistra) sono impostati. Una volta terminato, restituisce k se tutti i bit di n sono impostati e 2k in caso contrario.

Cominciamo riscrivendo la lambda f come una funzione denominata F , con una variabile ausiliaria 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)

In ogni invocazione di F , spostiamo prima il bit n di un totale di k unità a destra e memorizziamo il risultato in t . In questo modo, LSB 0 (t) = LSB k (n) , quindi t è dispari se e solo se è impostato LSB k (n) .

Determinare se MSB k (n) è impostato è leggermente più complicato; questo è ciò che n & t > t >> 1raggiunge. Per illustrare come funziona, consideriamo un numero intero n = 1αβγδεζη 2 di lunghezza bit 8 e analizziamo la chiamata di funzione F (n, 3) , ovvero k = 3 .

Stiamo cercando di determinare se MSB 3 (n) = γ è impostato esaminando il valore di verità del confronto (n & t> t >> 1) = (1αβγδεζη 2 & 1αβγδ 2 > 1αβγ 2 ) . Esaminiamo gli interi coinvolti.

MSB-index  012k4567

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

t >> 1         1αβγ

Sosteniamo che γ = 1 se e solo se n & t> t >> 1 .

  • Se γ = 1 , allora n & t ha una lunghezza in bit 5 mentre t >> 1 ha una lunghezza in bit 4 , quindi n & t> t >> 1 .

    Ciò dimostra che γ = 1 implica n & t> t >> 1 .

  • Se n & t> t >> 1 , ci sono due opzioni: γ = 1 o γ = 0 . Nel primo caso, non è rimasto nulla da dimostrare.

    Nel secondo caso, abbiamo che αβγδ 2 ≥ n & t> t >> 1 = 1αβγ 2 .

    Poiché αβγδ 2 > 1αβγ 2 , dobbiamo avere MSB 0 (αβγδ 2 ) ≥ MSB 0 (1αβγ 2 ) , il che significa che α = 1 .

    In questo modo, 1βγδ 2 > 11βγ 2 , quindi dobbiamo avere MSB 1 (1βγδ 2 ) ≥ MSB 1 (11βγ 2 ) , il che significa che β = 1 .

    A sua volta, ciò implica che 11γδ 2 > 111γ 2 . Ricordando che γ = 0 nel secondo caso, otteniamo la disuguaglianza 110δ 2 > 1110 2 , che è falsa poiché MSB 2 (110δ 2 ) = 0 <1 = MSB 2 (1110 2 ) .

    Pertanto, è possibile solo il primo caso e n & t> t >> 1 implica γ = 1 .

Riassumendo, se sono impostati sia LSB k (n) che MSB k (n) , t sarà dispari e n & t> t >> 1 sarà True , quindi t & (n & t> t >> 1) sarà resa 1 . Tuttavia, se LSB k (n) o MSB k (n) non è impostato (o se entrambi sono), t sarà pari o n & t> t >> 1 sarà Falso , quindi t & (n & t> t> > 1) produrrà 0 .

La chiamata a F con un singolo argomento inizializza k = 0 . Mentre la condizione di cui abbiamo discusso in precedenza vale, il codice successivo andviene eseguito, che (tra le altre cose) chiama ricorsivamente F con k incrementato .

Una volta che LSB k (n) o MSB k (n) non è impostato, la condizione fallisce e F (n, k) restituisce 0 . Ciascuna delle precedenti chiamate di funzione k aggiunge (n & (n + 1)> 0) + 1 a F (n, k) = 0 , quindi F (n) restituisce ((n & (n + 1)> 0) + 1) k .

Ora, se tutti i bit di n sono uguali (ovvero se n è 0 o tutti i suoi bit sono impostati), n + 1 non avrà alcun bit in comune con n , quindi n & (n + 1) = 0 e F (n) restituisce k . Tuttavia, se n ha sia bit impostati che non impostati, n & (n + 1)> 0 e F (n) restituisce 2k .


2
Le soluzioni ricorsive in Python sembrano segnare molto bene ultimamente.
mbomb007,

Almeno rispetto alle soluzioni iterative, hanno sempre. input(),, whilee printsono già 17 byte ...
Dennis

Sì, ma li trovo molto più difficili da scrivere.
mbomb007,

1
Giusto. Una semplice implementazione iterativa della stessa idea sarebbe però solo 5 byte più lunga. tio.run/nexus/… È possibile salvare altri 2 byte con pochi accorgimenti. tio.run/nexus/python2#JY1BDsIgFAXX7SnepgUUI1BNm1K4jKVJQ/…
Dennis

6

MATL , 13 12 byte

Btv`6L&)}x@q

Provalo online! Oppure verifica tutti i casi di test .

Spiegazione

Il codice ripete ogni cifra binaria e conta quante volte è possibile rimuovere due cifre esterne.

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)

6

Python, 82 byte

Sento che può ancora essere giocato a golf, ma ho trascorso un po 'di tempo a provare metodi diversi e questo è stato il più breve.

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

Provalo online

Sebbene funzioni in modo simile al programma Python dell'OP, l'ho creato prima che la domanda fosse pubblicata, dopo aver visualizzato la domanda nella Sandbox, che non conteneva un tale programma.


6

Python 2, 66 byte

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

Divide la rappresentazione binaria dell'input in blocchi di 1. Conta il numero di 1 nel più piccolo tra il primo e l'ultimo blocco, quindi lo raddoppia, a meno che non ci sia un singolo blocco che conterebbe il doppio.


Intelligente, ma comunque facile da capire. Mi piace!
mbomb007,

5
@ mbomb007 Prendilo come riscaldamento per capire Dennis's :)
xnor

3

PowerShell , 109 106 byte

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

Provalo online!

Riceve l'input $args[0], utilizza la chiamata NET per convertesso toStringcon la base 2(cioè, rendono binario), allora -splits che stringa 0s, negozi che in $a. Importante notare: la chiamata .NET non restituisce zeri iniziali, quindi la prima cifra è sempre a 1.

Vi sono quindi due possibilità: la stringa binaria è tutta una, oppure c'era almeno uno zero. Distinguiamo tra quelli con uno pseudo-ternario indicizzato da $a.count-eq1. Se il binario ha almeno uno zero, il caso sinistro, prendiamo il minimo della lunghezza della prima [0]stringa di se 1l'ultima [-1]stringa (trovata da |sorte quindi [0]). Il più corto di questi è il maggior numero di coppie che potremmo rimuovere, quindi lo moltiplichiamo per 2. Nota che se la stringa binaria originale termina in a 0, come per l'input 8, allora lo [-1].lengthsarà anche 0(poiché è una stringa vuota), che quando moltiplicata per 2è ferma 0.

Altrimenti, con la stringa binaria tutte, prendiamo solo $b(che in precedenza era impostato per essere la lunghezza della prima [0]stringa, in questo caso, l'intera stringa binaria).

In entrambe le situazioni, quel risultato viene lasciato sulla pipeline e l'output è implicito.


3

JavaScript (ES6), 57 byte

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>

Prende il binario e cerca di far corrispondere tutti 1so meno a un uguale numero di iniziali e finali 1s.


2

Retina , 48 byte

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

Provalo online

Spiegazione:

.+              # 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`

2

C #, 133 byte

Funzione che restituisce durezza. Prende intero dall'argomento.

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

Bene, oggi l'ho scoperto '1' + '1' = 98in C #.


1
Questo perché '1'è il carattere ASCII 49 e 49 + 49 = 98.
FlipTack

Ho letteralmente trascorso 10 minuti a capire perché il mio 1 + 1 = 2non ha funzionato. @FlipTack
devRicher

2

C, 89 88 85 byte

Due byte salvati grazie a @FlipTack che indica una dichiarazione inutile.

Chiama f()con il numero da testare, l'output viene restituito dalla funzione.

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

Provalo su ideone .


2

JavaScript (ES6), 59 58 byte

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

Casi test



2

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

È ora di iniziare a giocare a golf 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;}

Ecco la 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 l'uscita;

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

1

Java (OpenJDK) , 181 156 150 byte

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

Provalo online!


1

Mathematica, 63 56 byte

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

Spiegazione

l=#~IntegerDigits~2

Genera la rappresentazione base-2 dell'input, racchiusa in a List. Conservalo inl

(2-Min[...])

Se l'elemento min di lè 1, output 1. In caso contrario, output 2. Moltiplicalo per ...

Split[l]

Dividi lin piste.

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

Prendi il primo e l'ultimo elemento.

Tr/@ ...

Prendi il totale di entrambi.

Min[ ... ]

Trova il più piccolo tra i due.

(Moltiplica il primo risultato (1 o 2) per questo risultato).


1

Ottava, 56 54 byte

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

Provalo online!

Spiegazione:

d=dec2bin(n)-48

rappresentazione binaria di n

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

Prendi il minimo cumulativo d e il minimo cumulativo di capovoltod

res = cumd * cumfd ';

moltiplicare la matrice

out = res*2^!all(d)

moltiplicare per 2 se tutte le cifre sono 1;


@FlipTack Grazie, link aggiornato!
rahnema1,

1

Pyth, 18 byte

?*FJjQ2lJyhSxR0_BJ

Un programma che accetta l'input di un numero intero e stampa il risultato.

Suite di test (prima riga per la formattazione)

Come funziona

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

1

APL, 26 byte

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

Casi test:

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

Spiegazione:

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

                         ⊢ input
                    2⊥⍣¯1 converti in rappresentazione binaria
   ()
        (⊢ ¨⌽) per ogni bit e relativo bit corrispondente sull'altro lato
            (∧) prende il logico e di entrambi i bit,
             , crea un elenco di entrambi i bit,
              ∧ quindi prendere il e dell'elenco e il e
         ∊ appiattire l'array risultante
      ↑ ↑ prende solo i primi N bit, dove N è il
                                lunghezza dell'elenco originale di bit
    ∧ \ prendere una logica in esecuzione e (lasciando solo il
                                iniziando)
+ / ∘ somma quelli

1

J, 22 byte

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

Questo si basa sul trucco ordinato appreso da questa sfida .

Provalo online!

Spiegazione

(#<.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

1

PHP, 83 74 byte

3 + 6 byte salvati da Jörg

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

accetta input da STDIN; corri con -nR.

abbattersi

<?=                     # 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)

1
<?=~($s=decbin($argn))[$a=strspn($s,1)]?2*min($a,strspn(strrev($s),1)):$a;
Jörg Hülsermann,

0

JavaScript (ES6), 83 byte

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

0

Mathematica, 62 byte

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

Funzione pura dove #rappresenta il primo argomento.

(h=0;...;h)&imposta h=0, fa un sacco di cose ..., poi ritorna h(la durezza). Diamo un'occhiata al mucchio di cose:

#~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

Grazie a Greg Martin per avermi fatto conoscere questo trucco .


0

Haskell , 94 92 byte

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

Provalo online! Uso:

Prelude> sum.h.b $ 3167
4

Spiegazione:
b converte un numero in binario e restituisce un elenco di zero e di quelli con il bit meno significativo per primo. In h, questo elenco viene invertito e moltiplicato per elemento con l'elenco originale, quindi si span(>0)divide dopo i messaggi iniziali 1:

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

La tupla risultante è associata al modello in (c,_:_)cui _:_corrisponde a qualsiasi elenco non vuoto, quindi c = [1,1]. Poiché i byte vengono rimossi davanti e dietro, c++c = [1,1,1,1]viene restituito e infine sommato per produrre la durezza digitale .

Se il secondo elenco della tupla è vuoto, la rappresentazione binaria ne contiene solo una e il numero di quelle è la durezza digitale. Con la corrispondenza del modello fallito hrestituisce solo n, che viene nuovamente riassunto.


0

Perl, 61 byte

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

Il cuore di questo è la regex /^(1+).*\1$/dove 2 volte la lunghezza di $1è la risposta. Il resto del codice è sovraccarico e si occupa del caso speciale di tutti e 1.


È possibile omettere la parentesi attorno agli sprintfargomenti. Inoltre, l'uso di -pflag ti permetterà di scrivere un programma completo che sarà più breve della tua funzione in quanto sarai in grado di ometterlo sub f{...}(invece dovrai terminare con $_=...un miglioramento di 4 byte). Finalmente, invece del tuo length(...), puoi farlo /0/&&s/^(1+).*\1$/$1$1/;$_=y///c. Questo dovrebbe portarti a 51 byte.
Dada,


0

CJam, 14 byte

ri2b_0#\W%0#e<

Spiegazione:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.