如何从随机生成的字符中形成组合

本文关键字:字符 组合 随机 | 更新日期: 2023-09-27 18:16:13

我正在winforms应用程序中制作一个程序,在该程序中,它生成具有七个字符长度的随机模式,如2元音-5辅音、3元音-4辅音等。之后,它生成特定于生成的模式的随机字母。。

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

-样本输入-

图案:3V-4C字母:AIOLMNC组合:AIO AOL OIL。。。。邮件…索赔。。。。等等…

-输出-

发现的单词:油邮件索赔。。。等等…

这个程序适用于文字游戏。。我正在寻求帮助和任何可能帮助我解决问题的建议。我想不出正确的方法来启动算法以及如何对其进行编码。

如何从随机生成的字符中形成组合

我通常不会这么做,但我为您的问题找到了一个更好的解决方案,它值得自己的答案!这个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);
                    }
                }
            }
        }
    }
}

以下是算法摘要:

其基本思想是,每一组变位词都源自同一组字母
如果我们对字母进行排序,我们就可以把一组变位词组合在一起
我从组合变位词的算法中得到了这个想法
例如,可以在"AEMNS"上键入一组字谜("NAMES"、"MANES"、"MEANS"(
因此,一旦我们创建了字典查找,就可以非常容易和快速地求解变位词——只需对变位词的字母进行排序并执行查找。

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

这为我们提供了所有可能的字谜解决方案!

更新

这个解决方案直接回答了你的问题("我如何形成所有字符组合"(,但这不是一个非常有效的解决变位词的方法。我决定创建一个更好的解决方案来解决字谜,所以请看我的另一个答案。


这听起来像一个有趣的谜题
首先,以下是如何创建您的";"随机";输入:

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.另一个有用的资源是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文章有一个跳过重复的算法,但更复杂(。

正如你所说,最后一步是对照你的字典检查所有的排列。

优化

这个解决方案相当简单,如果你的谜题仍然很小,可能会非常有效。然而,它绝对是一个";暴力";这种方法,随着谜题越来越大,性能呈指数级下降!

  public static string RandomCharacters(int size = 5)
    {
        string alphabet = "abcdefgijkmnopqrstuvwxyz";
        Random ran = new Random();
       
       return       string.Join("",  (string.Join(',', alphabet.ToCharArray()) +
                     string.Join(',', alphabet.Reverse()) +
                     string.Join(',', alphabet.ToUpper().ToCharArray()) +
                     string.Join(',', shorturl_chars_ucase.ToUpper().Reverse())
                            ).Split(',')
                             .OrderBy(x => ran.Next(alphabet.Length * 4))
                             .Take(size)
                             .ToArray()
                              );
     }
        

随机字符(10(;