Toda su base biyectiva nos pertenece.


25

Fondo

Una numeración de base b biyectiva , donde b es un número entero positivo, es una notación posicional biyectiva que utiliza símbolos b con valores asociados de 1 a b .

A diferencia de su contraparte no biyectiva, ningún símbolo tiene un valor de 0 . De esta manera, cada número entero no negativo n tiene una representación única en la base biyectiva b .

Las numeraciones biyectivas populares incluyen la base unitaria biyectiva 2 (utilizada en la codificación de longitud de ejecución de bzip2 ) y la base biyectiva 26 (utilizada para numerar columnas en hojas de cálculo).

Definición

En este desafío, definimos el conjunto M de símbolos como

123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz<=>

y una función i de M al número natural tal que i ('1') = 1, ..., i ('>') = 64 .

Dada una base b entre 1 y 64 (ambos inclusive), definimos que cada número entero no negativo n corresponde a la cadena a k ... a 0 , que consiste en símbolos de M , de modo que n = b k i (a k ) + … + B 0 i (a 0 ) .

Esta correspondencia está bien definida y es biyectiva. Como una suma vacía se define como 0 , el entero 0 puede codificarse como una cadena vacía.

Tarea

Acepte tres cadenas como entrada:

  • Una base de entrada b entre 1 y 64 , codificada como una cadena de base 64 biyectiva .

  • Un número entero no negativo n , codificado como una cadena de base b biyectiva .

  • Una base de salida B entre 1 y 64 , codificada como una cadena de base 64 biyectiva .

Dadas estas tres entradas, codifique n como una cadena B de base biyectiva .

Casos de prueba

Todos los casos de prueba especifican la entrada en el orden b , n , B .

Input:  "4" "" "8"
Output: ""

Input:  "A" "16" "2"
Output: "1112"

Input:  "2" "122" "A"
Output: "A"

Input:  "3" "31" "1"
Output: "1111111111"

Input:  ">" "Fe" "a"
Output: "RS"

Reglas

  • Puede leer las tres cadenas en cualquier orden conveniente, como tal, una serie de cadenas, una representación de cadena de las mismas, concatenadas o separadas por delimitadores de un solo carácter de su elección.

  • Si elige imprimir la salida en STDOUT, solo puede imprimir los símbolos y (opcionalmente) una nueva línea final.

  • Se permiten conversiones de base incorporadas de todo tipo.

  • Aplican reglas estándar de .

Respuestas:


6

CJam, 43

qA,s"?[a{A<":,:^+:Mf#):B;(bLa{(Bmd)M=\j\+}j

3 bytes erradicados con la ayuda de Dennis :) Pruébelo en línea

Explicación:

La entrada se toma como bnBconcatenada en una sola cadena.

q           read the input
A,s         make an array of numbers from 0 to 9 and convert to string
"?[a{A<"    push this string, which contains the ends of 3 character ranges:
             uppercase letters: ['A'…'[')
             lowercase letters: ['a'…'{')
             "<=>": ['<'…'?')
             they're in a special order for the symmetric difference below
:,          for each character, make a range of all characters smaller than it
:^          fold/reduce these 6 ranges using symmetric difference
+           concatenate with the digits before
:M          save in M; this is like the M from the statement,
             except it starts with a zero (for matching indexes)
f#          find the indexes in M of all characters from the input string
)           take out the last value from the array
:B;         save it in B and pop it
(           take out the first value
b           use it as a base and convert the remaining array to a number
             this works even if some of the digits are not in the "normal" range
La{…}j      calculate with memoized recursion, using an empty string for value 0
  (         decrement the number
  Bmd       divide by B and get the quotient and remainder
  )         increment the remainder (this is the last digit in bijective base B)
  M=        get the corresponding character from M
  \j        swap with the quotient, and convert the quotient recursively
  \+        swap again and concatenate

Oh, ¿puedes usar el operador de conversión de base regular para la conversión de primera base? Ahora me siento tonto por usar todo el código que tengo en mi solución. :) No me di cuenta de que funcionaría con valores que están fuera del rango de la base. Bueno, en retrospectiva, no hay una buena razón por la que no debería.
Reto Koradi

@RetoKoradi sí, puedes hacer eso; algún día se documentará :)
aditsu

¿Te importa si cambio mi solución para usar la conversión base? Normalmente trato de evitar tomar ideas de otras soluciones. Pero realmente me molesta dejar que el mío se pare con un enfoque tan subóptimo. Es muy probable que su solución sea aún más corta.
Reto Koradi

@RetoKoradi no hay problema, adelante
aditsu

4

Pip, 84 80 78 bytes

m:J[,tAZLCAZ"<=>"]p:$+(m@?^b)*(m@?a)**RV,#bs:m@?cWn:px:(mn-(p:n//s-!n%s)*s).xx

Repositorio de GitHub para Pip

Algoritmos adaptados del artículo de Wikipedia. Aquí está la explicación de una versión anterior un poco descuidada:

                 Implicit: initialize a,b,c from cmdline args; t=10;
                 AZ=uppercase alphabet; x=""
m:               Build lookup table m:
 (J,t)             0123456789 (i.e. join(range(10)))...
 .AZ               plus A-Z...
 .LCAZ             plus lowercase a-z...
 ."<=>"            plus <=>
f:{              Define f(a,b) to convert a from bijective base b to decimal:
 $+                Sum of...
  (m@?^a)            list of index of each character of a in m
  *                  multiplied item-wise by 
  b**RV,#a           b to the power of each number in reverse(range(len(a)))
}
t:{              Define t(a,b) to convert a from decimal to bijective base b:
 x:""              Reset x to empty string (not needed if only calling the function once)
 Wa{               While a is not zero:
  p:a//b-!a%b        p = ceil(a/b) - 1 (= a//b if a%b!=0, a//b-1 otherwise)
  x:m@(a-p*b).x      Calculate digit a-p*b, look up the corresponding character in m, and
                     prepend to x
  a:p                p becomes the new a
 }
 x                 Return x
}
(t               Return result of calling t with these arguments:
 (f                Result of calling f with these arguments:
  b                  2nd cmdline arg
  m@?a)              1st cmdline arg's decimal value
 m@?c              3rd cmdline arg's decimal value
)
                 Print (implicit)

Ejecución de muestra:

dlosc@dlosc:~/golf$ python pip.py bijectivebase.pip ">" "Fe" "a"
RS

4

Octava, 166 bytes

function z=b(o,x,n)
M=['1':'9','A':'Z','a':'z','<=>'];N(M)=1:64;n=N(n);x=polyval(N(x),N(o));z='';while x>0 r=mod(x,n);t=n;if r t=r;end;z=[M(t),z];x=fix(x/n)-(r<1);end

Versión multilínea:

function z=b(o,x,n)
   M=['1':'9','A':'Z','a':'z','<=>'];
   N(M)=1:64;
   n=N(n);
   x=polyval(N(x),N(o));
   z='';
   while x>0
      r=mod(x,n);
      t=n;if r t=r;end;
      z=[M(t),z];
      x=fix(x/n)-(r<1);
   end
%end // implicit - not included above

En lugar de crear un mapa para convertir un carácter en un valor de índice, acabo de crear la tabla de búsqueda inversa Npara valores ascii 1..'z'y la llené con los índices en los valores apropiados.

polyval evalúa la ecuación

c 1 x k + c 2 x k-1 + ... + c k x 0

usando el valor de entrada convertido decimal como el vector de coeficientes cy la base original como x. (Desafortunadamente, Octave's base2dec()rechaza los símbolos fuera del rango normal).

Una vez que tenemos el valor de entrada en la base 10, el cálculo del valor en la nueva base es sencillo.

Conductor de prueba:

% script bijecttest.m
a=b('4','','8');
disp(a);
a=b('A','16','2');
disp(a);
a=b('2','122','A');
disp(a);
a=b('3','31','1');
disp(a);
a=b('>','Fe','a');
disp(a);

Resultados:

>> bijecttest

1112
A
1111111111
RS
>>

2

Perl, 261 248 229 bytes

sub t{$b=0;$b*=$_[1],$b+=ord($1=~y/0-9A-Za-z<=>/\0-A/r)while$_[0]=~/(.)/g;return$b}sub r{$n=$_[0];$n-=$m=($n-1)%$_[1]+1,$d=(chr$m)=~y/\0-A/0-9A-Za-z<=>/r.$d,$n/=$_[1]while$n;print$d}@a=split/,/,<>;r(t(@a[1],t@a[0],64),t@a[2],64)

multilínea, mientras que los bucles sin golf:

sub t{ # convert bijective base string to number
    $b=0;
    while($_[0]=~/(.)/g)
        {$b*=$_[1];$b+=ord($1=~y/0-9A-Za-z<=>/\0-A/r)}
    return$b}
sub r{ # convert number to bijective base string
    $n=$_[0];
    while($n)
        {$n-=$m=($n-1)%$_[1]+1;$d=(chr$m)=~y/\0-A/0-9A-Za-z<=>/r.$d;$n/=$_[1]}
    print$d}
@a=split/,/,<>; # parse input
r(t(@a[1],t@a[0],64),t@a[2],64)

tes una función para analizar un número de una cadena de base biyectiva de una base dada. res una función para generar una cadena de base biyectiva de una base dada a partir de un número. Los 3 parámetros separados por comas se analizan a partir de stdin y las funciones se invocan según sea necesario.

La conversión de un número positivo a una cadena de base biyectiva es similar a una base normal. Sin embargo, donde haría algo como esto para una base normal:

string s = ""
while(n)
{
    c = (n % base)
    s = (c + '0') + s
    n -= c // not necessary because the division will take care of it
    n /= base 
}

ajusta el mod para dar un rango de 1 a base en lugar de 0 a base - 1:

string s = ""
while(n)
{
    c = (((n-1) % base)+1)
    s = (c + '0') + s
    n -= c  // necessary in the case c = base
    n /= base 
}

2

Python 2, ... 317 307 298 311 bytes

Definitivamente golfable. Realmente odio cómo las cadenas no tienen asignación de elementos y las listas no find. Buscaré una mejor manera que mi solución rápida que tengo ahora.

Mi método es convertir la entrada a un número decimal, luego a la base de salida, luego convertirla a la base biyectiva.

Editar : Descubrí que mi programa no funcionaba al convertir a Unary. Cuesta 13 bytes arreglarlo e=F(o)<2, etc.

Pruébalo aquí

R=range;M="".join(map(chr,R(48,58)+R(65,91)+R(97,123)))+"<=>"
b,s,o=input()
F=M.find
e=F(o)<2
B=lambda n:n and B(n/F(o)-e)+M[n%F(o)+e]or""
n=B(sum(F(s[~j])*F(b)**j for j in R(len(s))))
i=n.find('0')
n=list(n)
while-~i:n=n[:i-1]+[M[F(n[i-1])-1]]+[o]+n[i+1:];n=n["0"==n[0]:];i="".join(n).find('0')
print"".join(n)

1
Estoy de acuerdo con tus manías de Python.
DLosc

@DLosc Gracias por la ayuda de golf.
mbomb007


Las listas tienen el .index()método. ¿Por qué no usar eso en lugar de buscar? Además, en lugar de guardar F(b)y F(o)en variables, solo las usa una vez, así que solo súbalas cuando sea necesario. Finalmente, 'n'[2::5]es más corto que ''.join(n)(reemplace los apóstrofes por backticks).
Kade

Además, creo que estás complicando demasiado esto ... La conversión de una cadena M biyectiva base b a decimal no debería tomar más de 35-40 bytes. Decimal a una cadena de base biyectiva B no será mucho más que eso.
Kade

2

Python 2, 167 bytes

No hay trucos especiales aquí realmente, excepto el [2::5]corte para obtener el conjunto de caracteres en un recuento de bytes más bajo.

x=range;A=`map(chr,x(49,58)+x(65,91)+x(97,123))`[2::5]+'<=>'
r=A.find
b,n,B=input()
B=r(B)+1
d=0;s=''
for c in n:d=d*-~r(b)+r(c)+1
while d:d-=1;s=A[d%B]+s;d/=B
print s

Pruebas:

"4","","8"     >>> (empty string)
">","Fe","a"   >>> RS
"3","31","1"   >>> 1111111111
"A","16","2"   >>> 1112
"2","122","A"  >>> A

2

CJam, 73 70 69 55 51 48 bytes

La última versión utiliza el operador de conversión de base CJam para la conversión desde la base de origen, que no había pensado hasta que vi la solución de @ aditsu. También aplica un consejo reciente de @Dennis para construir la cadena de "dígitos" ( /codegolf//a/54348/32852 ), así como algunas otras ideas compartidas en el chat.

lA,s'[,_el^+"<=>"+:Lf#Ll#bLl#:K;{(Kmd)L=\}hs-]W%

El formato de entrada es el valor, seguido de la base de origen y destino, con cada uno de ellos en una línea separada. Para la cadena vacía, deje la primera línea vacía. Entrada de ejemplo:

122
2
A

Pruébalo en línea

Explicación:

l       Get and interpret value from input.
A,s     Build the list of 64 "digits". Start with [0..9]
'[,     Build character sequence from \0 to Z.
_el     Lower case copy of the same sequence.
^       Symmetric set difference gives only letters from both sequences.
+       Concatenate with sequence of decimal digits, creating [0..9A..Za..z].
"<=>"   Remaining 4 characters.
+       Concatenate, resulting in full 64 character "digit" string.
:L      ... and store it in variable L for repeated use.
f#      Look up input characters in digit list.
Ll#     Get source base from input, and look up value in digit list.
b       Base conversion. This produces the input value.
Ll#     Get destination base from input, and look up value in digit list.
:K;     Store it in variable K for use in loop, and pop it off stack.
{       Loop for generating output digits.
  (       Decrement to get ceiling minus 1 after division.
  Kmd     Calculate divmod of current value with destination base.
  )       Increment mod to get 1-based value for digit.
  L=      Look up digit character for digit value.
  \       Swap. Digit stays on stack for output, remaining value is processed
          in next loop iteration until it is 0.
}h      End of loop for generating output digits.
s       Final value is 0. Covert it to a string.
-       And subtract it from second but last value. This eliminates the 0,
        as well as the second but last value if it was a \0 character.
]       Wrap digits in array.
W%      Reverse array, to get result from MSB to LSB.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.