我正在winforms应用程序中创建一个程序,在其中生成具有七个字符长度的随机模式,例如2Vowels-5consonants,3Vowels-4Consonants等等。之后它生成特定于生成的模式的随机字母。
生成字母后,我想列出所生成字母的所有可能字母组合..并尝试检查系统字典中是否存在生成的组合..
- 示例输入 -
模式:3V-4C字母:AIOLMNC 组合:AIO AOL OIL ....邮件 ....索赔....等等......
- 输出 -
找到的单词:OIL MAIL CLAIM ......等等......
此程序适用于文字游戏..我正在寻求帮助以及任何可以帮助我解决问题的建议。我想不出正确的方法来启动算法以及如何编码它。
答案 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有一个跳过重复的算法,但更复杂)。
正如您所说,最后一步是检查您字典中的所有排列。
这个解决方案相当简单,如果你的谜题仍然很小,它可能会很好用。然而,它绝对是一种“蛮力”的方法,随着拼图越来越大,性能呈指数级下降!