我正在尝试获取列表的所有预定义长度排列,仅按升序排列。
For example, take the set: "ABCDE"
I'd like the returning result to be:
ABC, ABD, ABE, ACD, ACE, ADE, BCD, BCE, BDE, CDE
换句话说,“B”永远不会出现在“A”(升序)之前,但我想要满足这一要求中的每一个变化。
我不想使用LINQ,我想找出实现这个的最快方法(速度是这个应用程序中的一个因素)。
到目前为止,我有一系列字符列表:
List<List<char>> Combinations;
其中内部“List”将是“ABC”(每个字母为char)的组合,外部列表将是所有组合的列表。
每个结果集的长度(上例中为3)需要是动态的,所以我认为我需要某种递归...我只是无法弄清楚如何实现它。 / p>
非常感谢任何帮助!
修改
到目前为止,这就是我所拥有的(我觉得我已经越来越近了......我真的无法让它真正构建最终列表(联盟不起作用 - 我是否正确使用它?) :
private List<List<char>> AscendingPermute(List<char> InMovements, int Combinations)
{
List<List<char>> Ret = new List<List<char>>();
for(int i = 0; i <= InMovements.Count - Combinations; i++)
{
if(Combinations <= 1){
Ret.Add(new List<char>() {InMovements[i] });
return Ret;
}
else
{
Ret.Union(AscendingPermute(InMovements.GetRange(1, InMovements.Count - 1), Combinations - 1));
}
}
return Ret;
}
我是否在正确的轨道上?我错过了什么?
谢谢!
答案 0 :(得分:5)
所以你想要一组n个元素中的所有可能的k元素,并且你想要按升序排列每个k元素列表?
看看这里:Algorithm to return all combinations of k elements from n
答案 1 :(得分:3)
我认为这就是你要找的东西,虽然我对速度并不乐观:
public static IEnumerable<string> GetPermutations(string letters, int max = 3, int curr = 0)
{
if (curr < max - 1)
{
for (int a = 0; a < letters.Length; a++)
{
string firstHalf = letters.Substring(a,1);
string subset = letters.Substring(a+1);
foreach (string secondHalf in GetPermutations(subset, max, curr + 1))
{
//Console.Write("1st: {0}, 2nd: {1}; set: {2}", firstHalf, secondHalf, subset);
yield return firstHalf + secondHalf;
}
}
}
else
yield return String.Empty;
}
示例电话:
foreach (var result in GetPermutations('ABCDE', 3)){
Console.WriteLine(result);
}
结果:
ABC
ABD
ABE
ACD
ACE
ADE
BCD
BCE
BDE
CDE
Press any key to continue...
答案 2 :(得分:2)
无需递归。
List<string> sortedResult = Perm("ABCDE",3);
static int BitCount(int n)
{
int test = n,count = 0;
while (test != 0)
{
if ((test & 1) == 1) count++;
test >>= 1;
}
return count;
}
static List<string> Perm(string input,int M)
{
var chars = input.ToCharArray();
int N = chars.Length;
List<List<char>> result = new List<List<char>>();
for (int i = 0; i < Math.Pow(2, N); i++)
{
if (BitCount(i) == M)
{
List<char> line = new List<char>();
for (int j = 0; j < N; j++)
{
if (((i >> j) & 1) == 1)
{
line.Add(chars[j]);
}
}
result.Add(line);
}
}
return result.Select(l => String.Join("", l)).OrderBy(s => s).ToList();
}
答案 3 :(得分:0)
您正在寻找一个递归函数,它将计算:给定字母表中的第一个字母(按升序排序)与升序排列连接,其中字母的其余部分少一个字母,加上剩余部分的上升排列相同的字母数。
为了澄清,您的例子是
asc_perm("ABCDE",3):="A"+asc_perm("BCDE",2) | asc_perm("BCDE",3)
要迭代编码,您可以使用n
和n>m => idx_{n} > idx_{m}
的约束将0 < n,m <= count(alphabet)
索引放入字母表中,并枚举所有可能的索引。它有点像一些额外的条件。要使用这些索引进行计数,请从1, 2, 3, 4, ...n
开始。从递增最后一个计数器开始,直到达到字母长度。如果是,请找到上一个索引,将其递增1,并将其后面的每个索引设置为1+idx_prev
,只要索引不会超过您的计数。如果是,则使用上一个索引重复该过程,直到用完有效位置。
您的示例的简单说明就是:
{1,2,3}
{1,2,4}
,{1,2,5}
{1,3,4}
{1,3,5}
{1,4,5}
{2,3,4}
{2,3,5}
{2,4,5}
{3,4,5}
答案 4 :(得分:0)
这是一个符合你想要的递归方法:
static IEnumerable<List<byte>> AscPerm(List<byte> inBytes, int combinations)
{
if (combinations == 1)
{
foreach (var b in inBytes)
{
yield return new List<byte> { b };
}
}
else
{
for (int i = 0; i <= inBytes.Count - combinations; i++)
{
// Recurse down, passing last items of inBytes.
var subPerms = AscPerm(inBytes.Skip(i +1).ToList(), combinations - 1);
foreach (var subPerm in subPerms)
{
List<byte> retBytes = new List<byte>{ inBytes[i] };
yield return retBytes.Concat(subPerm).ToList();
}
}
}
}
static void Main(string[] args)
{
var retList = AscPerm(new List<byte> { 1, 2, 3, 4, 5, 6, 7 }, 3);
foreach (var ret in retList)
{
foreach (var r in ret)
{
Console.Write(r);
}
Console.WriteLine();
}
Console.ReadLine();
}