【问题标题】:Breaking Down & Rearranging String into all possible combinations将字符串分解并重新排列为所有可能的组合
【发布时间】:2011-09-30 23:11:21
【问题描述】:

我想将一个字符串分解并重新排列成所有可能的组合

假设我有一个字符串:ABCDEF

我想把它分解并输出所有可能的组合

组合(6,6) = 1

ABCDEF

组合(6,5) = 6

BCDEF
ACDEF
ABDEF
ABCEF
ABCDF
ABCDE

组合(6,4) = 15

BCDE
ACDE
ABDE
ABCE
....
....
....
etc.

组合(6,3) = 20

BCD
ACD
...
etc.

组合(6,2) = 15 公元前 AB 等等

但是输出也必须按字母顺序排列。

我该怎么做?

谢谢!任何帮助将不胜感激!

【问题讨论】:

  • 暴力破解算法...不好。
  • 家庭作业?到目前为止你有什么?
  • 我正在为我的软件专业项目制作一个类似拼字游戏的游戏。我可以在字典中搜索一个单词。例如。搜索“ABDE”我会得到 BEAD、BADE、ABED。但是我想输入一个 6 个字母的单词并获得其中的所有组合
  • 我遇到了类似的问题,也许可以尝试将您的字典放入与字符顺序无关的格式(可能按字母顺序组织每个单词中的字母,然后输入字母计数在每个唯一的字母之后)。然后你只需用同样的方式格式化搜索。

标签: c# visual-studio algorithm math


【解决方案1】:

您可以从 Knuth Volume 4, Fascicle 3 中获得算法(实际上是其中的一些),但您必须将其从他的数学符号转换为 C#。

更新:当我想得更多时,Fascicle 2(生成排列)实际上更有帮助。您可以从http://www-cs-faculty.stanford.edu/~knuth/fasc2b.ps.gz 免费下载它,但您需要 gunzip 和 PostScript 预览器才能阅读它。生成字符串“ABCDE”的子集是很容易的部分。将其转换为数组 {'A', 'B', 'C', 'D', 'E'},从 0 到 2^N-1 运行 for 循环,其中 N 是数组长度,并处理每个值作为您要保留的元素的位掩码。因此 00001, 00010, 00011,... 给你 "A", "B", "AB",...

困难的部分是生成每个子集的所有排列,因此您会得到“ABC”、“BAC”、“CAB”等。蛮力算法(如其他答案之一)将起作用,但会得到如果字符串很长,则非常慢。 Knuth 有一些快速算法,如果最初对原始字符串进行排序,其中一些算法将按字母顺序生成排列。

【讨论】:

  • Scrabble 是排列而不是组合的情况。有e*n!结果不是这里建议的 2^n-1 。天真的解决方案是直截了当的,并且对于问题大小(7 个字母)完全易于处理,并且具有按字母顺序返回结果的好处,这是 OP 要求的。
  • @Gordy:OP 的 cmets 在他的问题之后解释说他有一本按排序字母序列索引的字典,因此他可以查找 ABDE 并获取列表 BEAD、BADE、ABED。鉴于此,他实际上不需要置换任何东西(我写答案时没有意识到)所以他没有 n!问题。他显然被困在寻找可用字母的子集,以形成更短的单词。
  • @Gordy:我承认我没有注意到 OP 指定了最大输入字符串长度。你是对的,这有很大的不同。
【解决方案2】:

好吧,扩展我的评论,我如何解决这个问题是将字符串转换为不关心字母顺序的哈希。哈希的工作原理是获取每个唯一的字母,然后是 :,然后是该字母出现的次数。

所以test = e:1,s:1,t:2

然后,如果有人查找世界 tset,它会生成相同的哈希 (e:1,s:1,t:2),然后你就有了匹配项。

我刚刚运行了一个单词列表(大约 2000 万个单词),为每个单词生成了一个哈希,并将其放入 mysql 表中,我可以找到一个单词的所有排列(仍然是单词本身,又名ered 将在几秒钟内返回 deerreed)。

【讨论】:

    【解决方案3】:

    您可以通过递增计数器并将计数器值转换为基数 n 来生成每个排列,其中 n 是输入中的字母数。丢弃任何包含重复字母的值,假设您的数组已排序,您剩下的是按字母顺序排列的可能拼字游戏单词。

    你必须数到 (n^(n-1))*(n+1) 才能得到 e*n!可能的拼字游戏。

    char[] Letters = new char[] { 'A', 'B', 'C', 'D', 'E', 'F' };
    
    // calculate e*n! (int)Math.Floor(Math.E * Math.Factorial(Letters.Length))
    int x = 0;
    for (int i = 1; i <= Letters.Length; i++)
        x = (x + 1) * i;
    
    for (int i = 1; x > 0; i++)
    {
        string Word = BaseX(i, Letters.Length, Letters);
        if (NoRepeat(Word))
        {
            Console.WriteLine(Word);
            x--;
        }
    }
    

    BaseX 返回给定 Base 和指定符号的 Value 的字符串表示形式:

    string BaseX(int Value, int Base, char[] Symbols)
    {
        StringBuilder s = new StringBuilder();
    
        while (Value > Base)
        {
            s.Insert(0, Symbols[Value % Base]);
            Value /= Base;
        }
    
        s.Insert(0, Symbols[Value - 1]);
        return s.ToString();
    }
    

    如果任何字母出现多次,NoRepeat 将返回 false:

    bool NoRepeat(string s)
    {
        bool[] Test = new bool[256];
    
        foreach (char c in s)
            if (Test[(byte)c])
                return false;
            else
                Test[(byte)c] = true;
    
        return true;
    }
    

    【讨论】:

      【解决方案4】:
      1. 按字母顺序对字符串进行排序。说 ABCDEF(你的例子)
      2. 准备索引和字符之间的映射

      地图[0] = 'A';地图[1] = 'B'; ... 地图[5] = 'F'

      3 .现在你的工作就简单多了:找出后面的数字大于前面的数字的所有组合

      组合(6,3):

      for (int i = 0; i < 6 - 2; i++)
          for (int j = i + 1; j < 6 - 1; j++)
              for (int k = j + 1; k < 6; k++)
              {
                  string strComb = map[i] + map[j] + map[k];
              }
      

      主要是这个想法,你可以用自己的方式改进。

      如果您想了解更多详情,请联系我!

      【讨论】:

        【解决方案5】:

        你可以用这个:

        static List<string> list = new List<string>();
        static string letters = "bcdehijkmnopqrstuvwxyz";
        static void Combine(string combinatory)
        {
            if(combinatory.Length < letters.Length)
            {
                Parallel.ForEach(letters, l =>
                {
                    if (!combinatory.Contains(l)) Combine(combinatory + l);
                }); 
            } else
            {
                list.Add(combinatory);
                Console.WriteLine(combinatory);
            }
        }
        

        它将添加到 list 列出所有可能的组合。

        然后您可以使用 Sort() 方法对列表进行排序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-18
          • 2011-07-04
          • 1970-01-01
          相关资源
          最近更新 更多