搜索列表中填充了随机放置字符的单词

时间:2014-06-10 23:56:37

标签: c# algorithm

我有一个问题:

如果我有一个字母列表,请填写:

A

T

C

我希望算法根据我给出的单词列表找出哪些组合创建单词(它们不必与列表的长度相同)

所以从这里开始就是这样:

CAT, ACT, A etc etc.

我遇到的问题是要了解算法的基础知识。

有谁知道如何帮助我开始这方面的工作?

5 个答案:

答案 0 :(得分:0)

当然,最简单的方法就是提到蛮力。但是,如果您使用的字母无法使用许多单词,则您不希望将随机字符串与整个字典进行比较。这里有一些技巧可以帮助您减少搜索空间。我会假设你只看英文单词。如果是这样,您可以使用一些通用语言结构来进一步减少搜索空间。现在,请记住,这些可能不会用英语中的所有字段,但如果您将自己的字典放在一起,则可以手动编写例外情况。

您要做的第一件事是删除在给定搜索集后无法生成的所有单词来减少您的字典。循环遍历每个字母和字典单词,看看单词是否包含字母。如果没有,请将其从字典中删除(这是使用并行库的一个很好的选择)。

接下来,从你的元音开始。每个单词至少有一个,并且可以将相对较少的方法分组。如果您不能使用您的字母对某个元音进行分组,请删除包含该组的任何单词。同时将蛮力发生器设置为仅查看有效的元音组合。

以' h'开头的单词总是(?)将元音作为第二个字母,所以不要将h(1)与除了a,e,i,o,u或y之外的任何东西联系起来。

除了c之后,我在e之前,虽然这个小案例我不认为值得加入,除非你说的话很长。

Q几乎总是紧随其后。

这些规则应该足以让您将搜索空间缩短90%或更多。然后,您可以使用与上述类似的语法规则来生成有效语法的组合,这将进一步减少您的空间。在那之后,即使有一个大词典(10万)单词和16个以上的字符,你应该有一个足够小的搜索空间来在一个不错的时间框架内运行强力算法。

不那么简单的方法

如果你真的想要花哨,你可以使用我上面提到的并行库来加速搜索空间的减少和强力算法本身。蛮力是令人尴尬的平行,所以如果你投入更多核心,你将在运行时获得近乎线性的改善。

除此之外,您可以尝试使用一些贝叶斯统计分析或神经网络来指导您的组合选择,但这可能对您之后的事情有些过分:)

答案 1 :(得分:0)

我不确定我是否理解你的问题。如果您想知道可以使用列表中的字符写入的所有可能单词,则需要包含所有单词的完整列表。一个简单的规则似乎是每个单词必须只使用字符列表中包含的字符。这样,您可以找到可以使用该字符列表编写的所有可能的字符串:

List<char> characters = new List<char>() { 'A', 'C', 'T', 'F', 'B', 'O' };
List<string> dictionary = new List<string>() { "CAT", "ACT", "A", "FISH", "BONE" };
List<string> possibleWords = new List<string>();

foreach (string word in dictionary)
{
   if (!(word.ToLower().Except(characters.ToString().ToLower()).Any()))
   {
      possibleWords.Add(word);
   }
}

// Result: "CAT", "ACT", "A"

答案 2 :(得分:0)

这是您的起点。它表明事实上,蛮力在这里很好。只有大约200,000个字要检查。对于完整的Scrabble单词列表,以下算法只需几毫秒,在字母表的前16个字母中查找匹配项:

class Program
{
    static void Main(string[] args)
    {
        var validWords = new List<string>(File.ReadAllText("AllWords.txt").Split(' '));

        foreach (var result in validWords.Where(word => 
                     IsWordInString(word, "ABCDEFGHIJKLMNOP")))
        {
            Console.WriteLine(result);   
        }
    }

    static bool IsWordInString(string word, string source)
    {
        var letterList = source.ToList();

        return word.All(letterList.Remove);
    }
}

算法是:

  • 遍历完整的有效字词列表
  • 检查单词中的每个字符是否都可以成功“删除”有效字符列表
  • 如果可以,那就是匹配。否则,它被拒绝了。

注意 - 这可能是最简单的方法,并且没有应用优化。有很多方法可以让它更快。但是因为它的性能主要取决于单词列表的长度(这是常数),所以增加字母列表对速度的影响非常小。

作为一个好奇心,如果你运行它(使用整个字母表):

var longest = validWords.Where(word => 
    IsWordInString(word, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
            .OrderByDescending(i => i.Length).First();

这会立即返回'DERMATOGLYPHICS' - 这是英语中最正确的最长单词,没有重复的字母。我的调试器中没有明显的执行时间。

(来自here的单词列表)

答案 3 :(得分:0)

我认为蛮力方法最简单。该算法基本上将查找您的一组字母的每个子集,并检查它是否在字典中。对于每个字母,它将检查它在单词中的可能性,而不是在单词中。

您的词典数据结构应该进行排序,以便可以使用二进制搜索快速检查是否包含单词(或者您可以使用哈希集)。

伪代码看起来像这样:

A = array of letters
S = empty list

IS_VALID(word, i)
    //base case: reached the end of the letters
    if i > length(A) - 1
        return

    if dictionary contains word
        add word to S

    //check for all words containing A[i]
    IS_VALID(w + A[i], i+1)
    //check for all words excluding A[i]
    IS_VALID(w, i+1);

//initialization
IS_VALID("", 0)

其中word是您当前查看的字符串,而iA中您当前正考虑追加到word末尾的字母索引

答案 4 :(得分:0)

    private static bool b;

    /// <summary>
    /// Word with Random Characters
    /// </summary>
    /// <param name="characterList"></param>
    /// <param name="wordList"></param>
    public static void WordWithRandomCharacters(List<char> characterList, List<string> wordList)
    {
        var resultWords = new List<string>();

        foreach (var word in wordList)
        {
            foreach (char c in word.ToCharArray())
            {
                b = false;
                if (characterList.Contains(c)) b = true;
                if (!b) break;
            }
            if (b) resultWords.Add(word);
        }

        foreach (var word in resultWords)
        {
            Console.WriteLine(word);
        }
    }