我面临的问题是创建一个有效的算法,该算法返回固定单词列表中的单词列表,该单词列表可以通过使用一组特定字母(此集合作为输入)拼写,此集合没有上限(或至少没有用)。
更具体地说,该算法需要实时提供解决方案以实现持续增加的输入,尽管只要前几个输出元件相对较快地输出,输出就可以缓慢地流出。
**注意:输入的实际扩充仅以添加到现有集合的形式发生。当选择一个单词时,LetterStock将耗尽所有使用的字母,并且该算法将从头开始运行。
可能的字符集是26个标准罗马字母。每个字母的库存可以是0->无穷大(适用于所有密集目的),每个字母只能使用一次(例如a,b,l不会返回“ball”,尽管a,bb,d,lll会)
正在使用的单词列表是不变的,因此如果任何预先计算的散列解决方案对于加快运行时性能有用,那么这是一个选项(尽管我想不出这样做的好方法)。但是,单词列表很大(~40,000个元素)。
到目前为止,我设计的最佳算法是使用字母库存数组的副本迭代整个单词集,并逐字母检查每个单词,耗尽副本库存并查看是否有任何字母在下面0.如果是这样,我继续前进,如果没有,我到达单词的末尾,我将该单词添加到解决方案集中。在完成整套文字后,我从头开始再次寻找可以拼写的单词,即我已经将一个或多个字符添加到我的LetterStock中。
// Pass in the string and a copy of the LetterStock 26-entry array
bool canBeSpelled(string str, int *letterStock)
{
for(int i=0; i<str.length; i++)
{
letterStock[str[i]-65]--; // deplete the letter stock for the given letter
if(letterStock[str[i]-65] < 0)
return false;
}
return true;
}
我的问题是:这个实施是否是最佳的,如果没有,哪个更好?
答案 0 :(得分:1)
稍微开箱即用,但您是否考虑使用Sqlite之类的东西进行文字存储/查询?可以解决你所有的问题
答案 1 :(得分:1)
我认为你需要directed acyclic word graph(或DAWG)。我25年前首次在Scrabble程序中使用了这个结构(我们从WordPerfect for DOS中获取了字典)。如果您发现很难从您的单词列表中构建DAWG,请不要放弃 - 这是一个非常令人满意的成就。
答案 2 :(得分:0)
轻微优化,但如果您知道您的字母数量为5且字母中的字母数为6,则无需检查该字词。
答案 3 :(得分:0)
您需要多快的解决方案?即使在检查所有字符的最坏情况下,您的示例仅需要几毫秒(在我的基本测试中为2毫秒)来检查40,000个单词中的所有字母(总共338,000个字母)。所以在一秒钟内你可以用掉1.7亿个字符的股票。
如果符合我的需要,我通常更喜欢一种更简单的算法,而不是花时间/精力寻找可能最终只会稍微好一点的“最佳”算法。
答案 4 :(得分:0)
一些预处理可能有助于加快用户的速度。
在字母类中有一本字典:
public Dictionary<char, int> count = new Dictionary<char, int> { {'a', 0}, {'b', 0}, etc
在你让用户将你的单词列表处理成一个由单词键入的字典之前,用一个值设置一个字母类:
List<string> strings = new List<string>{ "johnny", "happy", "people" };
Dictionary< string, letters> processedWordList;
void processList()
{
foreach (string s in strings)
{
//there should probably be a constructor in letters which does some of this
string lowered = s.ToLower();
Letters letters;
foreach (char c in lowered)
{
++letters.count[c];
}
processedWordList.Add(s, letters);
}
}
然后你可以覆盖字母类中的&gt; =运算符,看看你是否拼写单词:
public static bool operator >=(LetterCount c1, LetterCount c2)
{
foreach( KeyValuePair<char, int> letter in c1.count )
{
if (letter.Value < c2.count[letter.Key])
return false;
}
return true;
}
以类似的方式覆盖操作符以从输入中删除字母。然后您的主要功能如下:
foreach( string s in strings )
{
if (input >= processedWordList[s])
{
input = input - processedWordList[s];
}
}
当然,所有未经测试。
答案 5 :(得分:0)
可用字符集可能有多大?如果它很大,我的意思是如果你经常有15个或更多的字母,那么字典中很大一部分字词可能都适合,而蛮力,逐个检查可能是最有效的算法。另一方面,如果您的列表是商城,如果您通常在游泳池中只有4或5个字母,那么大多数单词都不会有质量,并且有一种方法可以放大候选词。
一种显而易见的方法是将字典放在索引表中。依次从池中取出每个独特的字母,并查找以该字母开头的单词。例如,如果池包含a,b,b,r,o,则查找以a开头的单词,然后是b,然后是r,然后是o。除此之外,我不确定您是否会通过更复杂的数据结构或搜索方案获得更多收益。