假设我有一个'abcd'字母,最大字符串长度为3.这给了我85 possible strings,包括空字符串。我想要做的是将[0,85]范围内的整数映射到我的字符串空间中的字符串,而不使用查找表。像这样:
0 => ''
1 => 'a'
...
4 => 'd'
5 => 'aa'
6 => 'ab'
...
84 => 'ddd'
如果字符串使用此伪代码算法固定长度,这很简单:
str = ''
for i in 0..maxLen do
str += alphabet[i % alphabet.length]
i /= alphabet.length
done
虽然当字符串的长度可以在[0,3]范围内的任何地方时,我无法找到一种好的,有效的方法。这将在随机输入的紧密循环中运行,因此我希望避免任何不必要的分支或查找。
答案 0 :(得分:2)
将索引移一,暂时忽略空字符串。所以你要映射0 -> "a", ..., 83 -> "ddd"
。
然后映射是
n -> base-4-encode(n - number of shorter strings)
有26个符号,这就是Excel列编号方案。
使用s
个符号,s + s^2 + ... + s^l
个非空字符串的长度最多为l
。抛开琐碎的案例s = 1
,这个总和是(几何系列的部分和)s*(s^l - 1)/(s-1)
。
因此,给定n
,找到最大l
,s*(s^l - 1)/(s-1) <= n
,即
l = floor(log((s-1)*n/s + 1) / log(s))
然后让m = n - s*(s^l - 1)/(s-1)
并将m
编码为基座l+1
中的s
- 符号字符串('a'〜&gt; 0,'b'〜&gt; 1 ,...)。
对于包含空字符串的问题,将0映射到空字符串,并将n > 0
编码n-1
映射到上面。
答案 1 :(得分:1)
在Haskell
encode cs n = reverse $ encode' n where
len = length cs
encode' 0 = ""
encode' n = (cs !! ((n-1) `mod` len)) : encode' ((n-1) `div` len)
检查:
*主&GT; map(编码“abcd”)[0..84] [“”,“a”,“b”,“c”,“d”,“aa”,“ab”,“ac”,“ad”,“ BA”, “BB”, “BC”, “BD”, “CA”, “CB”, “CC”, “CD”, “DA”, “DB”, “DC”, “DD”, “AAA” “AAB”, “AAC”, “AAD”, “ABA”, “羊毛”, “ABC”, “ABD”, “ACA”, “ACB”, “ACC”, “ACD”, “ADA”,”亚行”, “ADC”, “添加”, “咩”, “巴布”, “BAC”, “坏”, “BBA”, “BBB”, “BBC”, “BBD”, “BCA”, “BCB” “BCC”, “BCD”, “BDA”, “BDB”, “BDC”, “BDD”, “民航局”, “出租车”, “CAC”, “CAD”, “CBA”, “CBB”,” CBC”, “生物多样性公约”, “CCA”, “建行”, “CCC”, “CCD”, “综合发展区”, “国家开发银行”, “CDC”, “CDD”, “DAA”, “轻拍”, “DAC” “爸爸”, “DBA”, “DBB”, “DBC”, “当归补血汤”, “DCA”, “粑”, “DCC”, “DCD”, “多哈发展议程”, “DDB”, “DDC”,” DDD“]
答案 2 :(得分:0)
计算出每个长度的字符串数:N0,N1,N2和&amp; N3(实际上,你不需要N3)。然后,使用这些值来划分整数空间:0..N0-1的长度为0,N0..N0 + N1-1的长度为1,等等。在每个分区中,您可以使用固定长度的算法。 / p>
最糟糕的是,你大大减少了查找表的大小。
答案 3 :(得分:0)
这是一个C#解决方案:
static string F(int x, int alphabetSize)
{
string ret = "";
while (x > 0)
{
x--;
ret = (char)('a' + (x % alphabetSize)) + ret;
x /= alphabetSize;
}
return ret;
}
如果您想进一步优化,可能需要做一些事情来避免字符串连接。例如,您可以将结果存储到预先分配的char []数组中。