【问题标题】:generate all permutations of a word with wildcard使用通配符生成单词的所有排列
【发布时间】:2012-01-12 23:39:50
【问题描述】:

我需要找回我的密码,我知道一些字母,但忘记了我在其余部分中使用了哪些字符。我需要一种方法来生成密码的所有可能排列,给定一些已知字符和一些未知字符。例如,我想在文本框中输入像“mic??s??t”这样的短语,程序会生成所有可能的排列。在这种情况下,我知道只有几个字符可能用来代替这些问号,但我希望程序可以选择置换所有字符 AZ、az、0-9、/symbols/ 等,或者特定的字符集,如 EG、ty、1-4 等,通过第二个文本框作为字符串输入。

使用所有字符,它可能会生成一个类似的列表

micAAsAAt

micAAsABt

micAAsACT

micAAsADt

....

仅使用有限的字符集,例如 E-G,它看起来像

老鼠

老鼠EFt

小鼠EGt

小鼠场效应管

老鼠

....

如果这样做的唯一方法是生成每个排列周期,无论是否是通配符,对于 N 长度的单词,然后用正则表达式模式检查每个排列以过滤掉无用的,我可以接受(它会生成 256^N 个可能的组合)。否则,我宁愿能够仅使用递归(我需要帮助)来生成所有可能的数组。最后,我想生成这些排列的 txt 文件列表。我真的需要这里的递归帮助。我使用 C#。

【问题讨论】:

  • 这实际上是问号数量的幂。 ABCD? 在哪里?只能是 A-Z (26),最大组合为 26^1。

标签: c# wildcard permutation combinations


【解决方案1】:

这是一个融合了递归和迭代方法的简单解决方案。我想可以实现一个完全递归的解决方案,但我发现这种方法更容易理解。

//List of characters to substitute in place of '?'
List<char> validChars = new List<char>() { 'w', 'x', 'y', 'z' };
//List of combinations generated
List<string> combos = new List<string>();

void GenerateCombos(string mask, string combination)
{
    if (mask.Length <= 0)
    {
        //No more chars left in the mask, add this combination to the solution list.
        combos.Add(combination);
        return;
    }

    if (mask[0] != '?')
    {
        //This is not a wildcard, append the first character of the mask
        //to the combination string and call the function again with 
        //the remaining x characters of the mask.
        GenerateCombos(mask.Substring(1), combination + mask[0]);
    }
    else
    {
        //This is a wildcard, so for each of the valid substitution chars,
        //append the char to the combination string and call again
        //with the remaining x chars of the mask.
        validChars.ForEach(c => GenerateCombos(mask.Substring(1), combination + c));
    }
}

对函数的调用是:

string mask = "mic??s??t";
string combination = String.Empty;

GenerateCombos(mask, combination);

【讨论】:

    【解决方案2】:

    实际上是组合而不是排列。

    无论如何,为什么要使用递归?

    之所以使用递归,是因为我们可以想到一种以递归方式工作的解决方案,因此我们进行了匹配。通常编译器无法将其优化为更快、更小的迭代版本,但这通常没问题。但是,如果您自己想不出递归方法,那么为什么要寻求帮助而不是迭代方法呢?

    private IEnumerable<string> Combinations()
    {
        //Let's just use a-c for a test run.
        string setOfChars = "abc";
        //Let's return for four characters to guess for. We can change this.
        char[] buffer = new char[4];
        //We'll change these indices and then use them to pick chars from
        //setOfChars to the corresponding place in buffer
        int[] setOfIndices = new int[buffer.Length];
    
        //set up initial position:
        for(int i = 0; i != buffer.Length; ++i)
            buffer[i] = setOfChars[0];
    
        //return our inital position.
        yield return new string(buffer);
    
        //Now for our actual combinations.
        for(int i = 0; i != buffer.Length; ++i)
        {
            if(++setOfIndices[i] == setOfChars.Length)
                //if we've pushed an index out of range, then set it back to zero.
                setOfIndices[i] = 0;
            else
            {
                //otherwise move our position for changing things back to zero
                i = -1;
    
                //and generate our new combination.
                for(int j = 0; j != buffer.Length; ++j)
                buffer[j] = setOfChars[setOfIndices[j]];
                yield return new string(buffer);
            }
        }
    }
    

    这应该给我们 81 个不同的字符串(3 的 4 次方)。它确实如此。调用 Distinct() 以确保错误不会造成重复仍然给我们 81。快乐的日子。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-25
      • 2016-08-09
      • 1970-01-01
      相关资源
      最近更新 更多