W połowie odwróć ciąg binarny

12

To jest pytanie uzupełniające do mojego pytania Puzzling.SE : Zapytałem, czy istnieje funkcja f mapująca ciągi logiczne na ciągi logiczne, tak że f (f (b)) = rewers (b) dla wszystkich ciągów wejściowych b . (Przez odwrotność rozumiem funkcję odwracającą kolejność bitów.)

Powyższy link zawiera pozytywną odpowiedź, z dowodem, przez wielkie f '' , ale możesz zastanowić się nad tym pytaniem przed spojrzeniem.

Zaimplementuj taką funkcję f w jak najmniejszej liczbie bajtów.

  • Możesz albo odczytać dane wejściowe ze STDIN, albo wziąć argument funkcji; i albo napisz wynikowy ciąg do STDOUT, albo zwróć go.

  • Tak czy inaczej, możesz pracować z rzeczywistymi ciągami dwóch różnych bajtów lub znaków do wyboru (powiedz 0i 1, lub \x00i i \x01), lub z tablicami / listami wartości prawdziwych i fałszywych . Wybierz dwie wartości i trzymaj się ich.

  • Wynikiem pojedynczego zastosowania f musi być sam ciąg binarny: żadne głupie odpowiedzi, takie jak b -> if b starts with 'x' then reverse(b[1:]) else 'x' + b...

  • Twoja funkcja powinna być całkowita ; w szczególności wejściem może być pusty ciąg lub jeden bit długości itp. Nie ma górnej granicy długości łańcucha.

  • Powinno być również czyste : nie utrzymuj żadnego globalnego stanu między wywołaniami funkcji; ciąg wejściowy musi całkowicie określać ciąg wyjściowy.

Lynn
źródło
Czy wyjście może mieć inną długość niż wejście?
Luis Mendo,
Pewnie! (W przeciwnym razie wyzwanie jest niemożliwe do udowodnienia.)
Lynn,
Czy musi działać dla ciągów o długości jeden lub zero?
CalculatorFeline
Tak; funkcja musi być całkowita. Wyjaśniłem to w pytaniu!
Lynn,
1
Związane z.
Martin Ender,

Odpowiedzi:

7

Python 2, 64 69 bajtów

def f(s):p=(s+s).find(s,1);return[s[~p::-1],s+s[:p]][len(s)/p%2]

Nie golfowany:

def f(s):
    p = (s+s).find(s,1)
    n = len(s)/p
    return s[:p][::1|n%-2] * -~(n-1^1)

Znajduje to okres struny, tj. Minimalny ptaki, który sjest ciągiem długości ppowtarzanym nrazy (znalazłem metodę golfa na SO). Jeśli więc njest nieparzyste, dodaje to jeszcze jedno powtórzenie okresu. Jeśli njest równy, usuwa jedno powtórzenie okresu i odwraca go.

Dzięki @ Sp3000 za pomoc w implementacji mapowania funkcji między 1 <-> 2, 3 <-> 4 itd.

feersum
źródło
... Kiedy zostanie zaktualizowany nieoznakowany kod?
CalculatorFeline
@CatsAreFluffy Nie planuję modyfikować nielepszonego kodu, ponieważ używa tego samego pomysłu z niewielką różnicą. Z drugiej strony angielski jest aktualny.
feersum
2

Perl, 49 47 bajtów

Obejmuje +2 za -lp

Oparty na bardzo fajnym algorytmie @ feersum

Uruchom z wejściem na STDIN, np

perl -lp halfreverse.pl <<< "101001"

halfreverse.pl:

/^(.+?)((\1\1?)*)$/;$_=$3eq$1?reverse$2:$_.$1

Wyjaśnienie

/^               $/         Match the complete input string
  (.+?)                     Non-greedy match. Try only one digit at the start,
                            if that doesn't work try 2, then 3 etc. The string
                            being tried is remembered in backreference \1
       ((\1\1?)*)           Try to repeat \1 as many times as possible but
                            prefer in groups of 2. Fall back to only 1 at the
                            end of the string if the trailing part has an odd
                            number of \1 (so the total count is even)

   $3eq$1                   So the last match $3 equals the first match $1
         ?                  if and only if the total count is even
          reverse$2         If total count is even drop the first instance of
                   :        \1 and reverse
                    $_.$1   If total count is odd extend $_ by one instance
$_=                         Assign result
Ton Hospel
źródło
Jak to działa??
CalculatorFeline