Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 如何找到像自动完成一样最短的文本?_String_Algorithm - Fatal编程技术网

String 如何找到像自动完成一样最短的文本?

String 如何找到像自动完成一样最短的文本?,string,algorithm,String,Algorithm,我有一个字符串列表,我想找到最短的唯一方法来识别它们。这有点像自动完成,但对于给定的集合,它始终是最短的可识别方式 举个例子 PA for Paddington PE for Penryn PLO for Plymouth PLP for Plympton PO for Portsmouth Q for Quebec 我有几千个名字(不是城市,而是节目名) 我需要一个相对较短的顺序,这将是有序的(对于上面的列表,键和值都是有序的) 这方面的任何技术/算法都是有用的 我知道我必须(使用

我有一个字符串列表,我想找到最短的唯一方法来识别它们。这有点像自动完成,但对于给定的集合,它始终是最短的可识别方式

举个例子

PA  for Paddington
PE  for Penryn
PLO for Plymouth
PLP for Plympton
PO  for Portsmouth
Q   for Quebec
我有几千个名字(不是城市,而是节目名)

我需要一个相对较短的顺序,这将是有序的(对于上面的列表,键和值都是有序的)

这方面的任何技术/算法都是有用的

我知道我必须(使用PHP)编写代码,但只要我能理解算法,我就很高兴

我认为我必须按照当前的状态构建一个值树,然后开始一次导航一个字符,忽略具有单个选项的序列(例如普利茅斯/普利姆顿中的L和Y)


因此,从魁北克的Q开始,我会发现在整个树中,所有后续字母只使用一次,因此在该阶段Q就足够了。

您可以创建一个哈希表结构,将可能的子字符串映射到以该子字符串开头的所有名称的列表。这最终可能会成为一个相当大的数据结构,但由于您可以在到达唯一子字符串的那一刻短路,因此可以防止大小变得不合理地大。下面是一个使用C#的示例:

var name=new[]{
“帕丁顿”,
“彭林”,
“普利茅斯”,
“Plympton”,
“朴茨茅斯”,
“魁北克”};
//首先,对于任何给定的子序列,查找
//从它开始。
var groups=newdictionary();
我寻找新的团队;
List namesToProcess=names.ToList();
int i=0;
做
{
//一旦子字符串太长,就不要再看名字了。
namesToProcess=namesToProcess.Where(n=>n.Length>=i.ToList();
newGroups=namesToProcess.ToLookup(n=>n.Substring(0,i));
foreach(新组中的var g)
{
添加(g.Key,g.ToList());
}
//一旦我们发现只有名字,就别再看了
//匹配给定的子字符串。
namesToProcess=namesToProcess
.除(新组别)
.其中(g=>g.Count()==1)
.Select(g=>g.Single())
.ToList();
i++;
}while(newGroups.Any());
现在很容易查找与给定子序列匹配的项的数量,为任何给定的名称构建最佳代码是一项简单的任务。以空字符串开始,然后添加每个字母,这有助于缩小可能性的数量:

// Now build the best code to use for each name
var codeNamePairs = names.ToDictionary(n => 
{
    var sb = new StringBuilder();
    for(int j = 0; j < n.Length; j++)
    {
        var prefix = n.Substring(0, j+1);
        var withSamePrefix = groups[prefix];
        // Only add the next letter if it helps to narrow down
        // the possibilities
        if(withSamePrefix.Count != groups[sb.ToString()].Count)
        {
            sb.Append(n[j]);
        }
        if(withSamePrefix.Count == 1)
        {
            // Once we reach a prefix that's unique to this name,
            // then we know we've built the code we want.
            break;
        }
    }
    return sb.ToString();
});
//现在为每个名称构建最佳代码
var codeNamePairs=names.ToDictionary(n=>
{
var sb=新的StringBuilder();
对于(int j=0;j

我不确定代码翻译成PHP有多容易,但我希望我能很好地传达这个基本思想。

我会先按字母顺序对字符串排序。然后你就有了一个和你一样的清单:

Paddington
Penryn
Plymouth
Plympton
Portsmouth
Quebec
现在,对于从顶部开始的每个元素,我找到上一个和下一个元素都没有开始的最短字符串。在我们的例子中,它是这样的:

Paddigton
不能有
p
,因为下一个元素以它开头,但它可以有
Pa
,因为下一个元素不以它开头

对于
Penryn
我们从前面的id开始,减少足够多的字母,以
Penryn
开始-我们拿走
a
并保留
p
。现在我们重复:前面的元素以
P
开头,因此我们添加一个字母,得到
Pe
。在这种情况下,“上一个”和“下一个”都不以它开头,因此我们将此id分配给
Penryn

通过
Plymouth
,重复上述步骤,我们得到了
Plymo
id

在分析
Plympton
时,最初的上一个id缩减步骤将为我们提供
Plym
,我们只需要向其添加一个字母,以便上一个和下一个字母都不以该id开头

等等


现在,这不会产生与您建议的相同的id,但是在我看来,从算法的角度来看,PLO并不是普利茅斯的好id。

我真的很想知道为什么这个答案得到了-1票。谢谢您的这个过程。我用这些名字做了一棵字母树。然后我走到树上,挑出非唯一的字母来构建缩短的文本。对我来说非常有效。
Paddington
Penryn
Plymouth
Plympton
Portsmouth
Quebec