Подвійно, XOR і роби це знову


20

Ми визначаємо функцію g як g (n) = n XOR (n * 2) для будь-якого цілого числа n> 0 .

З огляду на x> 0 , знайдіть найменше ціле число y> 0 таке, що g k (y) = x для деякого k> 0 .

Приклад

x = 549

549 = 483 XOR (483 * 2)     (as binary: 1000100101 = 111100011 XOR 1111000110)
483 = 161 XOR (161 * 2)     (as binary:  111100011 =  10100001 XOR  101000010)

Що означає, що g 2 (161) = 549 . Ми не можемо йти далі, оскільки немає n такого, що g (n) = 161 . Отже, очікуваний вихід при x = 549 - y = 161 .

Правила

  • Ви не повинні підтримувати недійсні записи. Гарантоване існування пари (y, k) для вхідного значення x .
  • Це , тому найкоротша відповідь у байтах виграє!

Тестові кейси

     3 -->     1
     5 -->     1
     6 -->     2
     9 -->     7
    10 -->     2
    23 -->    13
    85 -->     1
   549 -->   161
   960 -->    64
  1023 -->   341
  1155 -->   213
  1542 -->     2
  9999 -->  2819
 57308 --> 19124
 57311 -->   223
983055 -->     1

3
Пов'язані OEIS: A048274, яка є послідовністюa(n) = g(n)
Джузеппе

Відповіді:


5

Java 8, 68 57 53 52 байт

n->{for(int i=0;i<n;)i-=(i*2^i)==n?n=i:-1;return n;}

-5 байт завдяки @ OlivierGrégoire .

Спробуйте в Інтернеті.

Пояснення:

n->{                 // Method with integer as both parameter and return-type
  for(int i=0;i<n;)  //  Loop `i` in the range (1,n)
    i-=(i*2^i)==n?   //   If `i*2` XOR-ed with `i` equals `n`
        n=i          //    Set `n` to `i`, and set `i` to 0 to reset the loop
       :             //   Else:
        -1;          //    Increase `i` by 1 to go to the next iteration
  return n;}         //  Return `n` after the entire loop

1
n->{for(int i=0;i<n;)i-=(i*2^i)==n?n=i:-1;return n;}(52 байти). Вибачте ^^ '
Олів’є Грегоар

@ OlivierGrégoire Ще розумніші, дякую!
Кевін Круїйсен

for(int i=0;n>i-=i+i^i^n?-1:n=i;);?
Тит

@Titus Я боюся, що це не буде працювати на Java (хоча я використовував такий підхід у своїй ітеративній відповіді на JavaScript ). У Java i+i^i^n?не булева, тому вона навіть не компілюється. Крім того, n>i-=...знадобляться круглі дужки ( n>(i-=...)), і n=iце не дозволено в іншому пункті терміналу, якщо тільки в пункті if (цей останній я не знаю чому, але це те, що це в Java, на жаль ).
Кевін Кройсейсен

1
@KevinCruijssen "і n=iне дозволено в іншому пункті терміналу, якщо". Тому що Java розбирає це як (i-=(i*2^i)!=n?-1:n)=iнезаконне.
Олів'є Грегоар


3

JavaScript, 53 байти

f=x=>(i=0,y=(G=x=>x&&(i^=x&1)+2*G(x>>1))(x),i?x:f(y))

Gє g^-1, який встановлений iв , 0якщо успіх, встановити iв 1разі невдачі.


1
Це був підхід , який я намагався використовувати , хоча я придумав версію з 50-байтовой: f=n=>(g=n=>n<2?0/!n:n%2+2*g(n/2^n%2))(n)?f(g(n)):n. На жаль нудний підхід на 12 байт коротший.
Ніл

3

Pyth , 13 12 10 байт

Збережено 1 байт завдяки @MrXcoder та ще 2 байти за їх пропозицією

fqQ.W<HQxy

Спробуйте в Інтернеті

Пояснення:

fqQ.W<HQxyZZT   Implicit: Q=eval(input()), trailing ZZT inferred

f               Return the first T in [1,2,3...] where the following is truthy
   .W       T     Functional while - loop until condition is true, starting value T
     <HQ            Condition: continue while iteration value (H) less than input
        xyZZ        Body: xor iteration value (Z) with double (y) iteration value (Z)
 qQ               Is the result of the above equal to input?

1
Ви можете скинути пробіл Tна 12 байт.
Містер Xcoder

3

R , 73 65 байт

f=function(x){for(i in 1:x)if(x==bitwXor(i,i*2)){i=f(i);break};i}

Спробуйте в Інтернеті!

Велике спасибі Джузеппе (-8) завдяки вашим твікам, таким простим, але дуже ефективним


1
на відміну від попередньої вашої відповіді, оскільки ця функція є рекурсивною, вам це потрібно, f=оскільки функція повинна бути зобов'язана fпрацювати належним чином. Це, як кажуть, приємна робота, і прийміть +1 від мене!
Джузеппе

2
ви також можете виконати повторне перемикання вашої логіки і дістати це до 65 байт
Джузеппе



2

C (gcc) , 57 56 55 51 байт

  • Збережено байт завдяки плафоні ; !=-.
  • Збережено байт п’ять байтів завдяки Рогем ; використовуючи потрійний вираз і примхи gcc.
X(O,R){for(R=1;R;O=R?R:O)for(R=O;--R&&(R^2*R)-O;);}

Спробуйте в Інтернеті!


1
+1 заX(O,R)
JayCe

@ceilingcat Гарна пропозиція, дякую.
Джонатан Фрех

for(R=1;R;O=R?R:O)зберігає байт.

R=O;врешті-решт, здається, це зайве, заощаджуючи ще 4 байти.

@Rogem Здається, дякую.
Джонатан Фрех

2

Z80Golf , 22 байти

00000000: 1600 1803 4216 007a b830 097a 82aa b828  ....B..z.0.z...(
00000010: f314 18f3 78c9                           ....x.

Порт відповіді Java @ KevinCruijssen

Приклад із введенням 9-спробуйте в Інтернеті!

Приклад із введенням 85-Спробуйте в Інтернеті!

Збірка:

;d=loop counter
;b=input and output
f:
	ld d,0
	jr loop
	begin:
	ld b,d
	ld d,0
	loop:
		ld a,d
		cp b
		jr nc,end	; if d==b end
		ld a,d
		add d		; mul by 2
		xor d
		cp b
		jr z,begin	; if (d*2)^d==b set b to d
		inc d
		jr loop
	end:
	ld a,b
	ret

Приклад складання для виклику функції та друку результату:

ld b,9 ; input to the function, in this case 9
call f
add 30h ; ASCII char '0'
call 8000h ; putchar
halt

Якщо aзамість цього зробити лічильник циклу d, ви можете замінити ld d,0інструкції xor aобома разів, що зберігає два байти.
Міша Лавров


1

JavaScript (Node.js), 48 45 38 байт

f=(n,i=0)=>i<n?i*2^i^n?f(n,i+1):f(i):n

-7 байт завдяки @Neil створивши рекурсивну версію моєї ітеративної версії нижче. Не працює для великих тестових випадків.

Спробуйте в Інтернеті.


Ітеративна версія 45 байт, яка працює для всіх тестових випадків:

n=>{for(i=0;i<n;)i-=i*2^i^n?-1:n=i;return n;}

Порт моєї відповіді на Java.
-3 байти завдяки @Arnauld .

Спробуйте в Інтернеті.


1
Ви можете i-=i*2^i^n?-1:n=i(але, на жаль, не на Java).
Арнольд

@Arnauld Зрозумів, що булеве в Java може бути якраз 1у JS. Спасибі!
Кевін Кройсейсен

1
38 байт, записаних рекурсивно (не працює для великих входів):f=(n,i=0)=>i<n?i*2^i^n?f(n,i+1):f(i):n
Ніл


1

Желе , 11 9 байт

BÄḂṛḄß$Ṫ?

Спробуйте в Інтернеті!

Поради: Використовуйте рекурсивну функцію замість петель.


Дуже швидко, на жаль, програє грубому підходу.

Зауважте, що:

  • Для x> 0 , f (x)> x .
  • popcount (f (x)) є парним, де popcount (n) - кількість бітів, встановлених у n .
  • Якщо n має навіть попконт, то існує x такий, що f (x) = n .
  • Нехай B (x) - двійкове представлення x , а Ṗ (l) - список l з вилученим останнім елементом. Тоді B (x) - накопичений XOR of (B (f (x))) .

Отже, ми неодноразово:

  • Обчисліть його бінарне подання ( B)
  • потім візьміть накопичений XOR (використовуйте ^\або ÄḂ, вони мають той же ефект).
  • Перевірте, чи ( ?) хвіст (останній елемент) ( ) накопиченого XOR є нульовим (непарний попконт)
    • Якщо так, перетворіть бінарний список назад у десятковий і повторно.
    • Якщо ні, повертає вхід ( ).


1

Четвертий (gforth) , 71 байт

: f 0 begin 2dup dup 2* xor = if nip 0 else 1+ then 2dup < until drop ;

Спробуйте в Інтернеті!

Пояснення

0                 \ add an index variable to the top of the stack
begin             \ start an indefinite loop
  2dup            \ duplicate the top two stack items (n and i)
  dup 2* xor =    \ calculate i xor 2i and check if equal to n
  if nip 0        \ if equal, drop n (making i the new n) and use 0 as the new i
  else 1+         \ otherwise just increment i by 1
  then            \ end the if-statement
  2dup <          \ duplicate the top two stack items and check if n < i
until             \ if previous statement is true, end the loop
drop              \ drop i, leaving n on top of the stack

1

Perl 6 , 44 байти

{({first {($^a+^2*$a)==$_},^$_}...^!*).tail}

Спробуй це

Розширено:

{  # bare block lambda with implicit parameter $_

  (
    # generate a sequence

    # no need to seed the sequence with $_, as the following block will
    # default to using the outer $_
    # $_, 

    { # parameter $_

      first
        {  # block with placeholder parameter $a

          ( $^a +^ 2 * $a ) # double (numeric) xor
          == $_             # is it equal to the previous value
        },

        ^$_  # Range up to and excluding the previous value ( 0..^$_ )
    }

    ...^  # keep doing that until: (and throw away last value)

    !*    # it doesn't return a trueish value

  ).tail  # return the last generated value
}



1

F #, 92 байти

let rec o i=
 let r=Seq.tryFind(fun x->x^^^x*2=i){1..i-1}
 if r.IsNone then i else o r.Value

Спробуйте в Інтернеті!

Рекурсивно перевіряє числа від 1 до i-1. Якщо є відповідність, перевірте, чи є менша для цього числа. Якщо немає відповідності, поверніть номер введення.


1

JavaScript (Node.js) , 40 байт

f=n=>g(n)%2?n:f(g(n)/2)
g=x=>x&&x^g(x/2)

Спробуйте в Інтернеті!

Дякую Шаггі за -1 байт.

Порт моєї відповіді на желе .

Нарешті, існує мова, де такий підхід коротший (на жаль ). (Я спробував Python та Java , це не працює)

Хтось може пояснити, чому я можу використовувати /2замість >>1?


1
x/2працює через арифметичний підтік. Будь-яке число IEEE 754 в підсумку буде оцінено як 0 при розділенні на достатньо 2 рази. (І десяткова частина просто ігнорується, коли XOR'd, тому це не впливає на результат.)
Арнольд


@Shaggy Здивований, що це працює. Я знаю, що це працює для Python та Lua тощо, але не Javascript.
користувач202729

falseПовернувся на останній ітерації неявно приводиться до 0шляхом побітового оператора XOR.
Кудлатий

@Shaggy Насправді ніхто falseне бере участь . JS &&поводиться майже однаково з Python / Lua and.
користувач202729

1

K (нг / к) , 32 26 байт

{$[*|a:2!+\2\x;x;2/-1_a]}/

Спробуйте в Інтернеті!

{ } - це функція з аргументом x

/ застосовує його до конвергенції

$[ ; ; ] якщо-то-інше

2\xдвійкові цифри x(це специфічно для ngn / k)

+\ часткові суми

2! мод 2

a: призначити a

*|останнє - зворотний ( |) та отримання першого ( *)

якщо вище 1, xбуде повернуто

інакше:

-1_a скинути останній елемент a

2/ декодувати двійкові


0

C, 62 байти

На основі Java Kevin Cruijssen:

int n(int j){for(int i=0;i<j;)i-=(i*2^i)==j?j=i:-1;return j;}

Перевіряти:

#include <stdio.h>
int n(int j);
#define p(i) printf("%6d --> %5d\n", i, n(i))
int main(void)
{
    p(3);
    p(5);
    p(6);
    p(9);
    p(10);
    p(23);
    p(85);
    p(549);
    p(960);
    p(1023);
    p(1155);
    p(1542);
    p(9999);
    p(57308);
    p(57311);
    p(983055);
}

Під час запуску тестова програма виводить:

     3 -->     1
     5 -->     1
     6 -->     2
     9 -->     7
    10 -->     2
    23 -->    13
    85 -->     1
   549 -->   161
   960 -->    64
  1023 -->   341
  1155 -->   213
  1542 -->     2
  9999 -->  2819
 57308 --> 19124
 57311 -->   223
983055 -->     1

C, 54 байти

Працює лише з C89 або K&R C:

n(j){for(i=0;i<j;)i-=(i*2^i)==j?j=i:-1;return j;}


int n(int j){for(int i=0;j>i-=i*2^i^j?-1:j=i;);return j;}Ці 57 байт працюють?
Тит

0

Мова Вольфрама (Mathematica) , 58 байт

Min[{#}//.x_:>Select[Range@#,MemberQ[x,#|BitXor[#,2#]]&]]&

Спробуйте в Інтернеті!

Починається зі списку, що містить лише дані. Ітеративно замінює список усіма цілими числами, які вже знаходяться в ньому, або відображають у ньому операцією подвійний і xor. Потім //.каже зробити це до досягнення фіксованої точки. Відповідь - найменший елемент результату.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.