您所有的双射基础都属于我们


25

背景

双射基地b记数,其中b是正整数,是双射位置符号,使得使用的b的符号与相关联的值1b

与它的非双义对应物不同,没有符号的值是0。这样,每个非负整数n在双射基数b中都有唯一的表示形式。

流行的双射数包括一进制双射基数2(用于bzip2的游程长度编码)和双射基数26(用于电子表格中的数字列)。

定义

在这个挑战中,我们将符号集M定义为

123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz<=>

和一个从M到自然数的函数i,使得i('1')= 1,…,i('>')= 64

给定一个介于164之间(包括两者之间)的b,我们定义每个非负整数n对应于字符串a k …a 0,由M的符号组成,因此n = b k i(a k)+ …+ b 0 i(a 0

这种对应关系是明确定义的并且是双射的。由于将空总和定义为0,因此整数0可以编码为空字符串。

任务

接受三个字符串作为输入:

  • 164之间的输入基b,被编码为双射基64字符串。

  • 非负整数n,被编码为双射基b字符串。

  • 164之间的输出基数B,被编码为双射基数64字符串。

给定这三个输入,将n编码为双射基B字符串。

测试用例

所有测试用例都按bnB的顺序指定输入。

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"

规则

  • 您可以按任何方便的顺序读取这三个字符串,例如,一个字符串数组,其字符串表示形式,由您选择的单字符定界符连接或分隔。

  • 如果选择将输出打印到STDOUT,则只能打印符号和(可选)尾随换行符。

  • 允许各种类型的基本转换内置。

  • 适用标准规则。

Answers:


6

CJam,43岁

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

在Dennis的帮助下根除了3个字节:) 在线尝试

说明:

输入为bnB,连接成单个字符串。

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

哦,您实际上可以将常规基本转换运算符用于第一个基本转换吗?现在,我对使用解决方案中的所有代码感到很傻。:)我没有意识到它可以使用超出基础范围的值。好吧,事后看来,没有充分的理由不应该这样做。
Reto Koradi 2015年

@RetoKoradi是的,你可以做到;有一天它将被记录在案:)
aditsu

您介意我更改解决方案以使用基本转换吗?我通常会尽量避免从其他解决方案中汲取灵感。但是,让我接受这种次优的方法确实让我感到困惑。您的解决方案很可能会更短。
Reto Koradi 2015年

@RetoKoradi没问题,继续前进
aditsu

4

点,84 80 78字节

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

Pip的GitHub存储库

从Wikipedia文章改编的算法。这是一个略微偏离版本的早期版本的说明:

                 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)

样品运行:

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

4

八度,166字节

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

多行版本:

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

我没有创建一个将字符转换为索引值的映射,而是创建了一个N用于ascii值的反向查找表,1..'z'并使用适当值的索引填充了它。

polyval 计算方程

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

使用十进制转换后的输入值作为系数向量,c原始底数为x。(不幸的是,Octave base2dec()拒绝了超出正常范围的符号。)

一旦我们以10为底的输入值,就可以很容易地计算出新底数的值。

测试驱动程序:

% 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);

结果:

>> bijecttest

1112
A
1111111111
RS
>>

2

Perl中,261个 248 229字节

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)

多行,而循环则不循环:

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)

t是从给定基数的双射基数字符串中解析数字的函数。r是从数字生成给定基数的双射基数字符串的函数。从stdin解析3个逗号分隔的参数,并根据需要调用函数。

将正数转换为双射基字符串类似于普通基。但是,对于普通的基准,您将在以下位置执行以下操作:

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 
}

您可以将mod调整为1到基本范围,而不是0到基本范围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字节

绝对可以打高尔夫球。我真的很讨厌字符串没有项目分配,列表没有find。与现在的快速修复方法相比,我将寻找一种更好的方法。

我的方法是将输入转换为十进制数,然后转换为输出基数,然后将其转换为双射基数。

编辑:发现我的程序转换为一元时不起作用。用修复的成本为13个字节e=F(o)<2,等等。

在这里尝试

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
我同意你的Python宠儿。
DLosc

@DLosc感谢您的高尔夫帮助。
mbomb007

这是代码保管吗?:P
Optimizer

列表具有.index()方法。为什么不使用它而不是查找?此外,而不是节约F(b)F(o)变量,你只能用一次,所以刚子他们在必要的。最后,'n'[2::5]短于''.join(n)(替换反引号的撇号)。
卡德2015年

另外,我认为您过于复杂了。从字符串M双射基数b到十进制的转换不应超过35-40个字节。十进制数为双射的基数B不会超过此数目。
卡德2015年

2

Python 2,167字节

除了在[2::5]切片时以较低字节数获取字符集外,此处实际上没有任何特殊技巧。

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

测试:

"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字节

最新版本使用CJam基本转换运算符从源基本进行转换,直到我看到@aditsu的解决方案之前,我才想到这一点。它还应用了@Dennis的最新技巧来构造“数字”字符串(/codegolf//a/54348/32852),以及在聊天中共享的其他一些想法。

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

输入格式是值,后跟源和目标库,它们各自位于单独的行上。对于空字符串,请将第一行留空。输入示例:

122
2
A

在线尝试

说明:

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.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.