我正在尝试编写一段代码来执行以下操作:
取数字0到9并为此数字指定一个或多个字母。例如:
0 = N,
1 = L,
2 = T,
3 = D,
4 = R,
5 = V or F,
6 = B or P,
7 = Z,
8 = H or CH or J,
9 = G
当我有像0123这样的代码时,对它进行编码是一件容易的事。它显然会构成代码NLTD。当引入像5,6或8这样的数字时,情况会有所不同。像051这样的数字会产生多种可能性:
NVL和NFL
很明显,对于包含5,6或8等几个数字的较长数字,这甚至会变得“更糟”。
在数学上相当糟糕,我还没有能够提出一个像样的解决方案,它允许我为程序提供一堆数字并让它吐出所有可能的字母组合。所以我会喜欢它的一些帮助,因为我似乎无法弄明白。挖出一些关于排列和组合的信息,但没有运气。
感谢您的任何建议/线索。我需要编写代码的语言是PHP,但任何一般提示都会受到高度赞赏。
更多背景知识:(并且非常感谢快速回复!)
我的问题背后的想法是构建一个脚本,帮助人们轻松地将他们想要记住的数字转换为更容易记住的单词。这有时被称为“伪数字学”。
我希望脚本能够为我提供所有可能的组合,然后将这些组合保存在已剥离的单词数据库中。这些被删除的单词来自字典,并且我在我的问题中提到的所有字母都被删除了。这样,要编码的数字通常可以容易地与一个或多个数据库记录相关。当这种情况发生时,您最终会得到一个单词列表,您可以使用这些单词来记住您想要记住的数字。
答案 0 :(得分:8)
可以很容易地递归完成。
这个想法是要处理大小为n的整个代码,你必须首先处理n - 1位数。 一旦你得到了n-1个数字的所有答案,就可以通过在最后一个字符上附加正确的字符来推断出整体的答案。
答案 1 :(得分:3)
实际上有一个更好的解决方案,而不是枚举数字的所有可能的翻译并查找它们:只需对字典中的每个单词进行反向计算,并将数字串存储在另一个字段中。所以如果您的映射是:
0 = N,
1 = L,
2 = T,
3 = D,
4 = R,
5 = V or F,
6 = B or P,
7 = Z,
8 = H or CH or J,
9 = G
您的反向映射是:
N = 0,
L = 1,
T = 2,
D = 3,
R = 4,
V = 5,
F = 5,
B = 6,
P = 6,
Z = 7,
H = 8,
J = 8,
G = 9
注意'ch'没有映射,因为'c'将被删除,'h'将被转换为8。
然后,您所要做的就是遍历字典单词中的每个字母,如果匹配则输出相应的数字,如果没有,则不执行任何操作。
将所有生成的数字字符串存储为数据库中的另一个字段。当你想要查找某些内容时,只需对输入的数字执行简单查询,而不必对潜在单词进行数十(或数百或数千)次查找。
答案 2 :(得分:2)
您想要保留号码的一般结构 - >字母赋值是一个或多个数组,类似于:
// 0 = N, 1 = L, 2 = T, 3 = D, 4 = R, 5 = V or F, 6 = B or P, 7 = Z,
// 8 = H or CH or J, 9 = G
$numberMap = new Array (
0 => new Array("N"),
1 => new Array("L"),
2 => new Array("T"),
3 => new Array("D"),
4 => new Array("R"),
5 => new Array("V", "F"),
6 => new Array("B", "P"),
7 => new Array("Z"),
8 => new Array("H", "CH", "J"),
9 => new Array("G"),
);
然后,一些递归逻辑给我们一个类似于:
的函数function GetEncoding($number) {
$ret = new Array();
for ($i = 0; $i < strlen($number); $i++) {
// We're just translating here, nothing special.
// $var + 0 is a cheap way of forcing a variable to be numeric
$ret[] = $numberMap[$number[$i]+0];
}
}
function PrintEncoding($enc, $string = "") {
// If we're at the end of the line, then print!
if (count($enc) === 0) {
print $string."\n";
return;
}
// Otherwise, soldier on through the possible values.
// Grab the next 'letter' and cycle through the possibilities for it.
foreach ($enc[0] as $letter) {
// And call this function again with it!
PrintEncoding(array_slice($enc, 1), $string.$letter);
}
}
三次欢呼!这将通过以下方式使用:
PrintEncoding(GetEncoding("052384"));
如果您真的想要它作为一个数组,请使用输出缓冲并使用“\ n”作为拆分字符串进行爆炸。
答案 3 :(得分:2)
这种问题通常通过递归来解决。在红宝石中,一个(快速和肮脏)的解决方案将是
@values = Hash.new([])
@values["0"] = ["N"]
@values["1"] = ["L"]
@values["2"] = ["T"]
@values["3"] = ["D"]
@values["4"] = ["R"]
@values["5"] = ["V","F"]
@values["6"] = ["B","P"]
@values["7"] = ["Z"]
@values["8"] = ["H","CH","J"]
@values["9"] = ["G"]
def find_valid_combinations(buffer,number)
first_char = number.shift
@values[first_char].each do |key|
if(number.length == 0) then
puts buffer + key
else
find_valid_combinations(buffer + key,number.dup)
end
end
end
find_valid_combinations("",ARGV[0].split(""))
如果你从命令行运行它,你将得到:
$ ruby r.rb 051
NVL
NFL
有关
答案 4 :(得分:1)
这是Python中的递归解决方案。
#!/usr/bin/env/python
import sys
ENCODING = {'0':['N'],
'1':['L'],
'2':['T'],
'3':['D'],
'4':['R'],
'5':['V', 'F'],
'6':['B', 'P'],
'7':['Z'],
'8':['H', 'CH', 'J'],
'9':['G']
}
def decode(str):
if len(str) == 0:
return ''
elif len(str) == 1:
return ENCODING[str]
else:
result = []
for prefix in ENCODING[str[0]]:
result.extend([prefix + suffix for suffix in decode(str[1:])])
return result
if __name__ == '__main__':
print decode(sys.argv[1])
示例输出:
$ ./demo 1
['L']
$ ./demo 051
['NVL', 'NFL']
$ ./demo 0518
['NVLH', 'NVLCH', 'NVLJ', 'NFLH', 'NFLCH', 'NFLJ']
答案 5 :(得分:0)
你能做到以下几点: 创建结果数组。 使用值“”
在数组中创建一个项目循环显示数字,比如051分别对每个数字进行分析。
每次在找到数字之间匹配1到1时,请为结果数组中的所有项添加正确的值。 所以“”变为N.
每次找到1到多个匹配项时,使用一个选项将新行添加到结果数组,并使用另一个选项更新现有结果。 因此,N成为NV,并且创建了一个新项目NF
然后最后一个数字是1比1匹配,因此结果数组中的项目变为 NVL和NFL
通过结果数组生成结果循环,打印它们或其他任何内容。
答案 6 :(得分:0)
让pn
成为给定数字字符串s
直到nth
数字的所有可能字母组合的列表。
然后,以下算法将生成pn+1
:
digit = s[n+1];
foreach(letter l that digit maps to)
{
foreach(entry e in p(n))
{
newEntry = append l to e;
add newEntry to p(n+1);
}
}
第一次迭代有点特殊情况,因为p -1 未定义。您只需将p 0 初始化为第一个字符的所有可能字符的列表。
所以,你的051例子:
迭代0:
p(0) = {N}
迭代1:
digit = 5
foreach({V, F})
{
foreach(p(0) = {N})
{
newEntry = N + V or N + F
p(1) = {NV, NF}
}
}
迭代2:
digit = 1
foreach({L})
{
foreach(p(1) = {NV, NF})
{
newEntry = NV + L or NF + L
p(2) = {NVL, NFL}
}
}
答案 7 :(得分:0)
您想要的表单可能类似于:
function combinations( $str ){
$l = len( $str );
$results = array( );
if ($l == 0) { return $results; }
if ($l == 1)
{
foreach( $codes[ $str[0] ] as $code )
{
$results[] = $code;
}
return $results;
}
$cur = $str[0];
$combs = combinations( substr( $str, 1, $l ) );
foreach ($codes[ $cur ] as $code)
{
foreach ($combs as $comb)
{
$results[] = $code.$comb;
}
}
return $results;}
这很丑,pidgin-php所以请先验证一下。基本思想是从[1..n]生成字符串的每个组合,然后在str [0]的每个可能代码的前面加上所有这些组合的前面。请记住,在最坏的情况下,这将使字符串的长度具有指数性能,因为在编码方案中实际存在很多歧义。
答案 8 :(得分:0)