Algorithm 算法问题:字母组合

Algorithm 算法问题:字母组合,algorithm,unique,combinations,Algorithm,Unique,Combinations,我正在尝试编写一段代码,它将执行以下操作: 取数字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或

我正在尝试编写一段代码,它将执行以下操作:

取数字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来编写代码,但任何一般性的提示都将不胜感激

更新: 更多背景:(非常感谢您的快速回复!)

我的问题背后的想法是建立一个脚本,帮助人们轻松地将他们想要记住的数字转换为更容易记住的单词。这有时被称为“伪命理学”


我想让脚本给我所有可能的组合,然后对剥离的单词数据库举行。这些被删去的单词来自一本字典,我在问题中提到的所有字母都被删去了。这样,要编码的数字通常可以很容易地与一个或多个数据库记录相关联。当这种情况发生时,你会得到一个单词列表,你可以用它来记住你想记住的数字。

这可以很容易地递归完成

其思想是,要处理大小为n的整个代码,必须首先处理n-1位数字。
一旦您得到n-1位的所有答案,就可以通过为最后一位添加正确的字符来推断整个答案。

您可以执行以下操作吗: 创建一个结果数组。 在数组中创建值为“”的项

循环浏览这些数字,比如051,逐个分析每个数字

每次找到数字之间的1对1匹配时,将正确的值添加到结果数组中的所有项。 所以“”变成了N

每次找到1对多匹配项时,使用一个选项向结果数组添加新行,并使用另一个选项更新现有结果。 因此N变为NV,并创建一个新项目NF

最后一个数字是1对1的匹配,因此结果数组中的项目将变为 NVL和NFL

要生成结果,请在结果数组中循环、打印结果或其他任何内容。

pn
成为给定数字字符串
s
n
位的所有可能字母组合的列表

然后,以下算法将生成
pn+1

第一次迭代有点特殊,因为p-1是未定义的。您只需将p0初始化为第一个字符的所有可能字符的列表

那么,您的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}
    }
}

要保存数字->字母分配的一般结构是一个或多个数组,类似于:

// 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);
    }
}
然后,一点递归逻辑为我们提供了一个类似于:

// 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);
    }
}

如果您确实想将其作为一个数组,请使用输出缓冲并使用“\n”作为拆分字符串进行分解。

您想要的格式可能类似于:

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;}

这是丑陋的,洋泾浜php,所以请先验证它。基本思想是从[1..n]生成字符串的每个组合,然后将str[0]的每个可能代码前置到所有这些组合的前面。请记住,在最坏的情况下,这将使性能在字符串长度上呈指数级增长,因为在编码方案中实际上存在很多歧义

诀窍不仅是生成与给定数字匹配的所有可能的字母组合,而且还要选择最容易记住的字母序列。建议在每个序列上运行算法,并尝试与英语词典进行匹配,以便找到最“真实的单词发音”序列。

这里是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']

这类问题通常通过递归来解决。在ruby中,一个(快速而肮脏的)解决方案是

@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

这与

有关,实际上有一个比列举一个数字的所有可能翻译并查找它们更好的解决方案:只需对字典中的每个单词进行反向计算,然后将数字字符串存储在另一个字段中。因此,如果您的映射是:

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
您的反向映射是:

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

然后,您所要做的就是遍历字典单词中的每个字母,如果匹配,则输出相应的数字,如果不匹配,则不执行任何操作


将所有生成的数字字符串存储为数据库中的另一个字段。当你想查找某个单词时,只需对输入的数字进行简单的查询,而不必对可能的单词进行数十次(或数百次或数千次)的查找。

这听起来确实是一个不错的面试问题。可以要求迭代和递归解决方案,并查看该人员提出了什么。我必须记住这一点这是不公平的,当我的大脑在循环中运行时,它总是运行得更好更快。特别是,天哪,又不是1:30了,是吗?是的,我该走了…为什么看起来每个人都会自动跳转到递归来解决这个问题?我是唯一一个这么想的人吗