Alterne alguns bits e obtenha um quadrado

26

Dado um número inteiro , você precisa encontrar o número mínimo de bits que precisam ser invertidos em para transformá-lo em um número quadrado . Você só pode inverter bits abaixo do mais significativo .NN>3N

Exemplos

  • N=4 já é um número quadrado ( ), portanto a saída esperada é . 0220 0
  • N=24 pode ser transformado em um número quadrado invertendo 1 bit: ( ), portanto a saída esperada é . 25 = 5 2 1110001100125=521
  • N=22 não pode ser transformado em um número quadrado invertendo um único bit (os resultados possíveis são , , e ), mas isso pode ser feito invertendo 2 bits: ( ), portanto a saída esperada é .20 18 30 10110 10 0 0 0 16 = 4 2 22320183010110100 00 00 016=422

Regras

  • Tudo bem se o seu código for muito lento ou gerar um erro para os casos de teste maiores, mas deve, no mínimo, suportar em menos de 1 minuto.3<N<10000
  • Isso é !

Casos de teste

    Input | Output
----------+--------
        4 | 0
       22 | 2
       24 | 1
       30 | 3
       94 | 4
      831 | 5
      832 | 1
     1055 | 4
     6495 | 6
     9999 | 4
    40063 | 6
   247614 | 7        (smallest N for which the answer is 7)
  1049310 | 7        (clear them all!)
  7361278 | 8        (smallest N for which the answer is 8)
100048606 | 8        (a bigger "8")

Ou no formato amigável de copiar / colar:

[4,22,24,30,94,831,832,1055,6495,9999,40063,247614,1049310,7361278,100048606]
Arnauld
fonte
Quase metade das respostas não são executadas 100048606no TIO, isso é um problema?
Magic Octopus Urn
@MagicOctopusUrn Obrigado, atualizei as regras para deixar mais claro que o suporte ao é opcional. N10000
Arnauld
1
Esta seria uma boa mais rápido código questão, bem como (sem a restrição de tamanho de entrada)
QWR
@qwr Sim, provavelmente. Ou se você quiser se tornar hardcore: dado , encontre o menor tal que . N f ( N ) = kkNf(N)=k
Arnauld

Respostas:

14

Ruby, 74 bytes

->n{(1..n).map{|x|a=(n^x*x).to_s 2;a.size>Math.log2(n)?n:a.count(?1)}.min}

Experimente online!

Isso simplesmente gera a sequência (que é muito mais que suficiente), XORs com e, em seguida, recebe o número de 1s em seu binário representação se o número de bits for menor ou igual a , ou caso contrário. Leva então o número mínimo de bits invertidos. Retornar vez do número de bits invertidos quando o bit mais alto invertido for maior que impede que esses casos sejam escolhidos como o mínimo, pois sempre será maior que o número de bits que possui. n log 2 nnn log 2 nn[12,22,,n2]nlog2nnnregistro2nn

Agradecemos a Piccolo por salvar um byte.

Maçaneta da porta
fonte
Você pode salvar um byte usando em (n^x*x).to_s 2;...vez de(n^x*x).to_s(2);...
Piccolo
@ Piccolo Não acredito que perdi isso, obrigado!
Doorknob
6

Gelatina , 12 bytes

²,BẈEðƇ²^B§Ṃ

Experimente online!

Confira uma suíte de testes!

Link monádico. Deve ser jogável. Mas sou burra demais para pensar em uma maneira de me livrar dos ³s. É a minha primeira resposta na qual uso com êxito o filtro / mapeamento / loop em geral, juntamente com uma cadeia diádica \ o /

Explicação

², BẈEðƇ² ^ B§Ṃ - Programa completo / Link monádico. Chame o argumento N.
     ðƇ - Mantenha o filtro [1 ... N] com a seguinte cadeia diádica:
², BẈE - O quadrado do item atual tem o mesmo comprimento de bit que N.
² - quadrado.
 , - Parear com N.
  B - Converta ambos em binário.
   Retr - Recupere seus comprimentos.
    E - E verifique se eles se igualam.
       ² ^ - Após a filtragem, quadracione os resultados e faça XOR com N.
         B - Representação binária de cada um.
          § - Soma de cada. Conta o número de 1s em binário.
           Minimum - mínimo.
Mr. Xcoder
fonte
5

Casca , 20 bytes

▼mΣfo¬→S↑(Mo¤ż≠↔ḋİ□ḋ

Experimente online!

Explicação

▼mΣf(¬→)S↑(M(¤ż≠↔ḋ)İ□ḋ) -- example input n=4
        S↑(           ) -- take n from n applied to (..)
                     ḋ  -- | convert to binary: [1,0,0]
                   İ□   -- | squares: [1,4,9,16,...]
           M(     )     -- | map with argument ([1,0,0]; example with 1)
                 ḋ      -- | | convert to binary: [1]
             ¤  ↔       -- | | reverse both arguments of: [1] [0,0,1]
              ż≠        -- | | | zip with inequality (absolute difference) keeping longer elements: [1,0,1]
                        -- | : [[1,0,1],[0,0,0],[1,0,1,1],[0,0,1,0,1],[1,0,1,1,1],....
                        -- : [[1,0,1],[0,0,0],[1,0,1,1],[0,0,1,0,1]]
    f(  )               -- filter elements where
       →                -- | last element
      ¬                 -- | is zero
                        -- : [[0,0,0]]
 mΣ                     -- sum each: [0]
▼                       -- minimum: 0
ბიმო
fonte
▼mΣfo¬←ṠMz≠ȯfo£İ□ḋπŀ2Lḋeconomiza 2 bytes. RIP você pontuação quadrada perfeita.
Mr. Xcoder
@ Mr.Xcoder: Vergonha com o placar .. Mas me livrei de mais alguns, agora com o
objetivo de
5

Perl 6 , 65 bytes

{min map {+$^a.base(2).comb(~1) if sqrt($a+^$_)!~~/\./},^2**.msb}

Experimente online!

Eu me sinto um pouco suja por testar um quadrado perfeito, procurando por um período na representação de seqüência de caracteres da raiz quadrada do número, mas ... qualquer coisa para raspar bytes.

Sean
fonte
4

05AB1E , 20 15 bytes

Lnʒ‚b€gË}^b€SOß

-5 bytes graças a @ Mr.Xcoder usando uma porta de sua resposta Jelly .

Experimente on-line ou verifique todos os casos de teste (os três maiores casos são removidos porque atingem o tempo limite após 60 segundos; ainda leva cerca de 35 a 45 segundos com os outros casos de teste).

Explicação:

L            # Create a list in the range [1, input]
             #  i.e. 22 → [0,1,2,...,20,21,22]
 n           # Take the square of each
             #  i.e. [0,1,2,...,20,21,22] → [0,1,4,...,400,441,484]
  ʒ     }    # Filter this list by:
   ,         #  Pair the current value with the input
             #   i.e. 0 and 22 → [0,22]
             #   i.e. 25 and 22 → [25,22]
    b        #  Convert both to binary strings
             #   i.e. [0,22] → ['0','10110']
             #   i.e. [25,22] →  ['10000','11001']
     g      #  Take the length of both
             #   i.e. ['0','10110'] → [1,5]
             #   ['10000','11001'] → [5,5]
       Ë     #  Check if both are equal
             #   i.e. [1,5] → 0 (falsey)
             #   i.e. [5,5] → 1 (truthy)
^            # After we've filtered, Bitwise-XOR each with the input
             #  i.e. [16,25] and 22 → [6,15]
 b           # Convert each to a binary string again
             #  i.e. [6,15] → ['110','1111']
  S         # Change the binary strings to a list of digits
             #  i.e. ['110','1111'] → [['1','1','0'],['1','1','1','1']]
    O        # Take the sum of each
             #  i.e. [['1','1','0'],['1','1','1','1']] → [2,4]
ß            # And then take the lowest value in the list
             #  i.e. [2,4] → 2
Kevin Cruijssen
fonte
1
Ok, então, um válido de 15 Byter: Lnʒ‚b€gË}^b€SOß. Ele quebra o seu conjunto de testes, infelizmente, embora
Mr. Xcoder
1
@ Mr.Xcoder Obrigado! E minha suíte de testes quase sempre quebra depois que eu jogo alguma coisa .. XD Mas agora está corrigido também.
Kevin Cruijssen 9/08/19
Eu acho que eu não sou bom em escrever conjuntos de testes em 05AB1E ¯ \ _ (ツ) _ / ¯, agradável-lo de que você fixa-lo :)
Mr. Xcoder
3

Java (JDK 10) , 110 bytes

n->{int i=1,s=1,b,m=99,h=n.highestOneBit(n);for(;s<h*2;s=++i*i)m=(s^n)<h&&(b=n.bitCount(s^n))<m?b:m;return m;}

Experimente online!

Olivier Grégoire
fonte
1
Você pode salvar 1 byte usando bit a bit e &, em vez de lógica e&&
kirbyquerby
3

Gaia , 18 bytes

Perto do porto da minha resposta Jelly .

s¦⟪,b¦l¦y⟫⁇⟪^bΣ⟫¦⌋

Experimente online!

Demolir

s¦⟪, b¦l¦y⟫⁇ ^ bΣ⟫¦ - Programa completo. Vamos chamar a entrada N.
s¦ - Esquadra cada número inteiro no intervalo [1 ... N].
  ⁇⟫⁇ - Selecione aqueles que atendem a uma determinada condição, quando executados
                     um bloqueio diádico. O uso de um bloco diádico economiza um byte porque o
                     input, N, é implicitamente usado como outro argumento.
   , - Emparelhe o elemento atual e N em uma lista.
    b¦ - Converta-os em binário.
      ... - Consiga seus comprimentos.
        y - Depois verifique se são iguais.
           - ⟫¦ - Execute todos os números inteiros válidos através de um bloco diádico.
            ^ - XOR cada um com N.
             bΣ - Converta em binário e soma (conte os 1s em binário)
                 ⌋ - Mínimo.
Mr. Xcoder
fonte
2

Braquilog , 56 41 bytes

Não vai quebrar nenhum recorde, mas pensei em publicá-lo de qualquer maneira

⟨⟨{⟦^₂ᵐḃᵐ}{h∋Q.l~t?∧}ᶠ{ḃl}⟩zḃᶠ⟩{z{∋≠}ᶜ}ᵐ⌋

Experimente online!

Kroppeb
fonte
Acabei de perceber que fechar é uma coisa. Eu vou encurtá-lo depois que eu voltar do jantar
Kroppeb
1
@ Arnauld Sim, o principal problema era que, para cada i na faixa (0, n + 1), recalculava a faixa, ao quadrado e ao binário. Colocando isso fora recuired mais alguns bytes, mas é muito mais rápido agora
Kroppeb
2

montagem x86-64, 37 bytes

Bytecode:

53 89 fb 89 f9 0f bd f7 89 c8 f7 e0 70 12 0f bd
d0 39 f2 75 0b 31 f8 f3 0f b8 c0 39 d8 0f 42 d8
e2 e6 93 5b c3

Bem, isso calcula até o exemplo mais alto em menos de um segundo.

O coração do algoritmo é xor / popcount, como de costume.

    push %rbx
    /* we use ebx as our global accumulator, to see what the lowest bit
     * difference is */
    /* it needs to be initialized to something big enough, fortunately the
     * answer will always be less than the initial argument */
    mov %edi,%ebx
    mov %edi,%ecx
    bsr %edi,%esi
.L1:
    mov %ecx,%eax
    mul %eax
    jo cont     /* this square doesn't even fit into eax */
    bsr %eax,%edx
    cmp %esi,%edx
    jnz cont    /* can't invert bits higher than esi */
    xor %edi,%eax
    popcnt %eax,%eax
    cmp %ebx,%eax   /* if eax < ebx */
    cmovb %eax,%ebx
cont:
    loop .L1
    xchg %ebx,%eax
    pop %rbx
    retq
ObsequiousNewt
fonte
Sugira a substituição de pelo menos um de seus movs por umxchg
tetocat 31/08/18
Pelo que sei, há apenas um que salvaria um byte ( mov %ecx,%eax) e não posso deixar% ecx morrer lá.
precisa saber é o seguinte
1

Wolfram Language (Mathematica) , 67 bytes

Min@DigitCount[l=BitLength;#~BitXor~Pick[s=Range@#^2,l@s,l@#],2,1]&

Experimente online!

{1,2,...,n}BitLengthPickBitXorMinDigitCount1

JungHwan Min
fonte
1

Carvão , 31 bytes

NθI⌊EΦEθ↨×ιι²⁼LιL↨θ²ΣE↨責⁼λ§ιμ

Experimente online! Link é a versão detalhada do código. Explicação:

Nθ                              Input N
       θ                        N
      E                         Map over implicit range
          ιι                    Current value (twice)
         ×                      Multiply
        ↨   ²                   Convert to base 2
     Φ                          Filter over result
               ι                Current value
                  θ             N
                 ↨ ²            Convert to base 2
              L L               Length
             ⁼                  Equals
    E                           Map over result
                       θ        N
                      ↨ ²       Convert to base 2
                     E          Map over digits
                           λ    Current base 2 digit of N
                             ι  Current base 2 value
                              μ Inner index
                            §   Get digit of value
                          ⁼     Equals
                         ¬      Not (i.e. XOR)
                    Σ           Take the sum
   ⌊                            Take the minimum
  I                             Cast to string
                                Implicitly print
Neil
fonte
1

Gelatina , 20 bytes

BL’Ø.ṗŻ€©Ḅ^⁸Ʋa§ɼ¹ƇṂ

Experimente online!

Erik, o Outgolfer
fonte
1

Japonês -g , 20 bytes

Isso pode ser jogado para baixo.

op f_¤Ê¥¢lî^U ¤¬xÃn

Experimente online!

Luis felipe De jesus Munoz
fonte
1

C (gcc) ,  93  91 bytes

g(n){n=n?n%2+g(n/2):0;}m;i;d;f(n){m=99;for(i=0;++i*i<2*n;m=g(d=i*i^n)<m&d<n/2?g(d):m);n=m;}

Experimente online!


Edit: Eu acho que minha solução original ( Experimente on-line! ) Não é válida, porque uma das variáveis m, global para salvar alguns bytes por não especificar o tipo, foi inicializada fora f(n)e, portanto, teve que ser reinicializada entre as chamadas


Código não comentado e comentado:

g(n){n=n?n%2+g(n/2):0;} // returns the number of bits equal to 1 in n
m; //miminum hamming distance between n and a square
i; //counter to browse squares
d; //bitwise difference between n and a square
f(n){m=99; //initialize m to 99 > size of int (in bits)
    for(
        i=0;
        ++i*i<2*n; //get the next square number, stop if it's greater than 2*n
        g(d=i*i^n)<m&&d<n/2&&(m=g(d)) //calculate d and hamming distance
//      ^~~~~~~~~~~^ if the hamming distance is less than the minimum
//                    ^~~~^ and the most significant bit of n did not change (the most significant bit contains at least half the value)
//                           ^~~~~~~^ then update m
       );
    n=m;} // output m

Edições:

  • Economizou 2 bytes graças a ceilingcat
Annyo
fonte