打破&将String重新排列为所有可能的组合

时间:2011-07-08 03:05:37

标签: c# visual-studio algorithm math

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

说我有一个字符串: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     等

然而,ouptut也必须按字母顺序排列。

我将如何做到这一点?

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

5 个答案:

答案 0 :(得分:4)

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

更新:当我更多地考虑这个问题时,分册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有一些快速算法,如果首先对原始字符串进行排序,其中一些将按字母顺序生成排列。

答案 1 :(得分:2)

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

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

然后如果有人在寻找世界tset,它会生成相同的哈希值(e:1,s:1,t:2),并且bam你有匹配。

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

答案 2 :(得分:1)

您可以通过递增计数器并将计数器值转换为基数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;
}

答案 3 :(得分:0)

  1. 按字母顺序对字符串进行排序。说ABCDEF(你的例子)
  2. 在索引和字符之间准备地图
  3. map [0] ='A'; map [1] ='B'; ... map [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];
            }
    

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

    如果您想了解更多细节,请与我联系!

答案 4 :(得分:0)

你可以使用这个:

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);
    }
}

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

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