如何用随机生成的字符组合组合?

时间:2011-12-01 05:10:46

标签: c#

我正在winforms应用程序中创建一个程序,在其中生成具有七个字符长度的随机模式,例如2Vowels-5consonants,3Vowels-4Consonants等等。之后它生成特定于生成的模式的随机字母。

生成字母后,我想列出所生成字母的所有可能字母组合..并尝试检查系统字典中是否存在生成的组合..

- 示例输入 -

  

模式:3V-4C字母:AIOLMNC   组合:AIO AOL OIL ....邮件   ....索赔....等等......

- 输出 -

  

找到的单词:OIL MAIL CLAIM ......等等......

此程序适用于文字游戏..我正在寻求帮助以及任何可以帮助我解决问题的建议。我想不出正确的方法来启动算法以及如何编码它。

2 个答案:

答案 0 :(得分:2)

我通常不会这样做,但我想出了一个更好的解决方案来解决你的问题,它应该得到自己的答案!这个AnagramSolver解决方案比我的其他答案更优化,因为它不会创建单词的每一个单一排列,并且字典查找非常优化。试试吧:

用法示例:

string[] dictionary = ReadDictionary(...);
var solver = new AnagramSolver(dictionary);

int minimumLength = 1;
IEnumerable<string> results = solver.SolveAnagram("AEMNS", minimumLength);

// Output the results:
foreach (var result in results)
{
    Console.WriteLine(result);
}
// Output example: 
// "NAMES", "MANES", "MEANS", "AMEN", "MANE", "MEAN", "NAME", "MAN", "MAE", "AM", "NA", "AN", "MA", "A",

代码:

public class AnagramSolver
{
    public AnagramSolver(IEnumerable<string> dictionary)
    {
        // Create our lookup by keying on the sorted letters:
        this.dictionary = dictionary.ToLookup<string, string>(SortLetters);
    }

    private ILookup<string, string> dictionary;

    public IEnumerable<string> SolveAnagram(string anagram, int minimumLength)
    {
        return CreateCombinations(anagram, minimumLength)
            // Sort the letters:
            .Select<string, string>(SortLetters)
            // Make sure we don't have duplicates:
            .Distinct()
            // Find all words that can be made from these letters:
            .SelectMany(combo => dictionary[combo])
            ;
    }

    private static string SortLetters(string letters)
    {
        char[] chars = letters.ToCharArray();
        Array.Sort(chars);
        return new string(chars);
    }

    /// <summary> Creates all possible combinations of all lengths from the anagram. </summary>
    private static IEnumerable<string> CreateCombinations(string anagram, int minimumLength)
    {
        var letters = anagram.ToCharArray();

        // Create combinations of every length:
        for (int length = letters.Length; length >= minimumLength; length--)
        {
            yield return new string(letters, 0, length);
            // Swap characters to form every combination:
            for (int a = 0; a < length; a++)
            {
                for (int b = length; b < letters.Length; b++)
                {
                    // Swap a <> b if necessary:
                    char temp = letters[a];
                    if (temp != letters[b]) // reduces duplication
                    {
                        letters[a] = letters[b];
                        letters[b] = temp;
                        yield return new string(letters, 0, length);
                    }
                }
            }
        }
    }

}

以下是该算法的摘要:

基本思想是每一组字谜都来自同一组字母 如果我们对字母进行排序,我们可以将各组字母组合在一起 我从Algorithm for grouping anagram words得到了这个想法 例如,一组字谜(“NAMES”,“MANES”,“MEANS”)可以键入“AEMNS”。
因此,一旦我们创建了字典查找,解决字谜非常容易和快速 - 只需对字谜的字母进行排序并执行查找。

接下来的挑战是找到所有“较小”的字谜 - 例如,找到“NAME”,“SANE”,“MAN”,“AN”,“A”等。 这可以通过找到anagram的所有组合来完成 组合比排列更容易找到。不需要递归。我实现了3个循环和简单交换的完整组合!需要一段时间才能使算法正确,但现在已经清理完了,它非常漂亮 对于找到的每个组合,我们必须再次对字母进行排序并执行查找。

这为anagram提供了所有可能的解决方案!

答案 1 :(得分:0)

更新

此解决方案直接回答了您的问题(“我如何形成所有字符组合”),但这不是解决字谜的非常有效的方法。我决定为解决字谜创造一个更好的解决方案,所以请看我的其他答案。


这听起来像个有趣的谜题 首先,您可以通过以下方式创建“随机”输入:

Random rng = new Random();
const string vowels = "AEIOU";
const string consonants = "BCDFGHJKLMNPQRSTVWXYZ";
string CreatePuzzle(int vowelCount, int consonantCount){

    var result = new StringBuilder(vowelCount + consonantCount);
    for (int i = 0; i < vowelCount; i++) {
        result.Append(vowels[rng.Next(5)]);
    }
    for (int i = 0; i < consonantCount; i++) {
        result.Append(consonants[rng.Next(21)]);
    }

    return result.ToString();
}

然后你需要创建这些字母的所有排列。这对于递归来说非常棒。以下代码是我在http://www.cut-the-knot.org/do_you_know/AllPerm.shtml找到的Heap算法的实现。另一个有用的资源是http://www.codeproject.com/KB/recipes/Combinatorics.aspx

/// <summary>
/// Returns all permutations of the puzzle.
/// Uses "Heap's Algorithm" found at http://www.cut-the-knot.org/do_you_know/AllPerm.shtml
/// </summary>
IEnumerable<string> CreatePermutations(string puzzle) {
    // It is easier to manipulate an array; start off the recursion:
    return CreatePermutations(puzzle.ToCharArray(), puzzle.Length);
}
IEnumerable<string> CreatePermutations(char[] puzzle, int n) {
    if (n == 0) {
        // Convert the char array to a string and return it:
        yield return new string(puzzle);
    } else {
        // Return the sub-string:
        if (n < puzzle.Length) {
            yield return new string(puzzle, n, puzzle.Length - n);
        }
        // Create all permutations:
        for (int i = 0; i < n; i++) {
            // Use recursion, and pass-through the values:
            foreach (string perm in CreatePermutations(puzzle, n-1)) {
                yield return perm;
            }
            // Create each permutation by swapping characters: (Heap's Algorithm)
            int swap = (n % 2 == 1) ? 0 : i;
            char temp = puzzle[n-1];
            puzzle[n-1] = puzzle[swap];
            puzzle[swap] = temp;
        }
    }
}

请注意,此算法不检查重复项,因此像“AAA”这样的输入仍将导致6个排列。因此,在结果上调用.Distinct()可能是有意义的(尽管CodeProject article有一个跳过重复的算法,但更复杂)。

正如您所说,最后一步是检查您字典中的所有排列。

优化

这个解决方案相当简单,如果你的谜题仍然很小,它可能会很好用。然而,它绝对是一种“蛮力”的方法,随着拼图越来越大,性能呈指数级下降!