Переключите несколько битов и получите квадрат

26

Учитывая целое число , вы должны найти минимальное количество битов, которые нужно инвертировать в чтобы превратить его в квадратное число . Вам разрешено инвертировать только биты ниже самого значимого .NN>3N

Примеры

  • 2 2 0N=4 уже является квадратным числом ( ), поэтому ожидаемый результат равен .220
  • 11000 1100 1 25 = 5 2 1N=24 можно превратить в квадратное число путем инвертирования 1 бита: ( ), поэтому ожидаемый результат равен .110001100125=521
  • 23 20 18 30 10110 10 0 0 0 16 = 4 2 2N=22 не может быть преобразовано в квадратное число путем инвертирования одного бита (возможные результаты - , , и ), но это может быть сделано путем инвертирования 2 битов: ( ), поэтому ожидаемый результат равен .23201830101101000016=422

правила

  • Хорошо, если ваш код слишком медленный или выдает ошибку для больших тестовых случаев, но он должен по крайней мере поддерживать менее чем за 1 минуту.3<N<10000
  • Это !

Контрольные примеры

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

Или в удобном для копирования / вставки формате:

[4,22,24,30,94,831,832,1055,6495,9999,40063,247614,1049310,7361278,100048606]
Arnauld
источник
Почти половина ответов не выполняется для 100048606TIO, это проблема?
Волшебная Урна Осьминога
@MagicOctopusUrn Спасибо, я обновил правила, чтобы прояснить, что поддержка является необязательной. N10000
Арно
1
Это был бы также хороший вопрос с быстрым кодом (без ограничения размера ввода)
qwr
@qwr Да, наверное. Или, если вы хотите пойти в хардкор: с учетом найдите наименьшее N такое, что f ( N ) = k . kNf(N)=k
Арно

Ответы:

14

Рубин, 74 байта

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

Попробуйте онлайн!

Это просто генерирует последовательность (которой гораздо больше, чем достаточно), XOR ее с n , а затем принимает либо число 1 в своем двоичном представлении, если число бит меньше чем или равно log 2 n , или n в противном случае. Затем требуется минимальное количество перевернутых битов. Возврат n вместо числа переброшенных битов, когда максимальный переброшенный бит больше, чем log 2 n, предотвращает выбор этих случаев в качестве минимума, так как n[12,22,,n2]nlog2nnnlog2nn всегда будет больше, чем количество битов, которые у него есть.

Спасибо Piccolo за сохранение байта.

Дверная ручка
источник
Вы можете сохранить байт, используя (n^x*x).to_s 2;...вместо(n^x*x).to_s(2);...
Piccolo
@Piccolo Не могу поверить, что я пропустил это, спасибо!
Ручка двери
6

Желе , 12 байт

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

Попробуйте онлайн!

Проверьте набор тестов!

Монадическая ссылка. Должно быть пригодным для игры в гольф. Но я слишком глуп, чтобы думать о способе избавиться от ³с. Это мой первый ответ, в котором я успешно использую фильтрацию / отображение / цикл в целом вместе с диадической цепочкой \ o /

объяснение

², BẈEðƇ² ^ B§Ṃ - Полная программа / монадическая ссылка. Назовите аргумент Н.
     ðƇ - Filter-keep [1 ... N] со следующей диадической цепочкой:
², BẈE - квадрат текущего элемента имеет ту же длину в битах, что и N.
² - Площадь.
 , - Пара с Н.
  B - преобразовать оба в двоичный файл.
   Ẉ - Получить их длины.
    E - И проверь, равняются ли они.
       ² ^ - После фильтрации возведите в квадрат результаты и присвойте им X
         Б - двоичное представление каждого.
          § - Сумма каждого. Подсчитывает количество единиц в двоичном
           Ṃ - Минимум.
Мистер Xcoder
источник
5

Шелуха , 20 байт

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

Попробуйте онлайн!

объяснение

▼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
ბიმო
источник
▼mΣfo¬←ṠMz≠ȯfo£İ□ḋπŀ2Lḋэкономит 2 байта. Покойся с миром, ты идеальный квадратный результат.
Мистер Кскодер
@ Mr.Xcoder: Стыдно за счет ... Но я избавился от еще нескольких, теперь нацеливаясь на 16; P
ბიმო
5

Perl 6 , 65 байт

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

Попробуйте онлайн!

Я чувствую себя немного грязным из-за того, что проверяю идеальный квадрат, ища точку в строковом представлении квадратного корня числа, но ... что-нибудь, чтобы сбрить байты.

Шон
источник
4

05AB1E , 20 15 байт

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

-5 байт благодаря @ Mr.Xcoder, использующему порт своего ответа Jelly .

Попробуйте онлайн или проверьте все тестовые случаи (три самых больших тестовых случая удалены, потому что они истекают через 60 секунд; все еще занимает приблизительно 35-45 секунд с другими тестовыми случаями).

Объяснение:

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
Кевин Круйссен
источник
1
Хорошо, действительный 15-byter: Lnʒ‚b€gË}^b€SOß. К сожалению, он нарушает ваш тестовый набор
Мистер Xcoder
1
@ Mr.Xcoder Спасибо! И мой тестовый комплект почти всегда ломается после того, как я что-то играю в гольф ... XD Но теперь это тоже исправлено.
Кевин Круйссен
Думаю, я не очень хорошо пишу тестовые наборы в 05AB1E ¯ \ _ (ツ) _ / ¯, приятно, что вы это исправили :)
Mr. Xcoder,
3

Java (JDK 10) , 110 байт

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

Попробуйте онлайн!

Оливье Грегуар
источник
1
Вы можете сохранить 1 байт, используя побитовое и &вместо логического и&&
kirbyquerby
3

Gaia , 18 байт

Рядом с портом моего желе ответ .

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

Попробуйте онлайн!

Сломать

s¦⟪, b¦l¦y⟫⁇ ⟪^ bΣ⟫¦⌋ - Полная программа. Давайте назовем вход N.
s¦ - возведите в квадрат каждое целое число в диапазоне [1 ... N].
  Select⟫⁇ - выберите тех, которые удовлетворяют определенному условию
                     диадический блок. Использование двоичного блока экономит один байт, потому что
                     input N неявно используется в качестве другого аргумента.
   , - Соединить текущий элемент и N в списке.
    b¦ - конвертировать их в двоичный файл
      l Get - Получи их длины.
        y - Затем проверьте, равны ли они.
           Run ⟫¦ - Выполнить все действительные целые числа через двоичный блок.
            ^ - XOR каждый с N.
             bΣ - конвертировать в двоичную и суммировать (считать 1 в двоичном)
                 ⌋ - Минимум.
Мистер Xcoder
источник
2

Брахилог , 56 41 байт

Он не побьет рекорды по длине, но думал, что я все равно выложу

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

Попробуйте онлайн!

Kroppeb
источник
Просто понял, молнии это вещь. Я сокращу его после того, как вернусь из закусочной
Кроппеб
1
@Arnauld Да, главная проблема заключалась в том, что для каждого i в диапазоне (0, n + 1) я пересчитывал диапазон, возводил его в квадрат и в двоичную форму. Помещение этого извне потребовало еще несколько байтов, но теперь это стало намного быстрее
Kroppeb
2

сборка x86-64, 37 байт

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

Хорошо, это вычисляет даже самый высокий пример менее чем за секунду.

Сердцем алгоритма, как обычно, является xor / popcount.

    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
источник
Предложите заменить хотя бы одного из ваших movнаxchg
--catcat
Насколько я могу судить, есть только один, который спас бы byte ( mov %ecx,%eax), и я не могу позволить% ecx умереть там.
ObsequiousNewt
1

Древесный уголь , 31 байт

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

Попробуйте онлайн! Ссылка на подробную версию кода. Объяснение:

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
Нил
источник
1

C (gcc) ,  93  91 байт

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

Попробуйте онлайн!


Редактировать: я думаю, что мое оригинальное решение ( попробуйте онлайн! ) Недопустимо, потому что одна из переменных m, глобальная для сохранения нескольких байтов без указания типа, была инициализирована вне f(n)и, следовательно, должна была быть повторно инициализирована между вызовами


Развернутый и прокомментированный код:

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

Редактирование:

  • Сэкономлено 2 байта благодаря функциюcatcat.
Annyo
источник