数组中3个值的组合

时间:2014-05-02 14:32:59

标签: c# arrays boolean

var example = new[]{1, 1, 1, 0, 1, 1}

我想生成一个所有数组的数组,这个数组在这个数组的位置组合中有三个1,在所有其他位置都有0。

在这个例子中,这些将是:

1 1 1 0 0 0
1 1 0 0 1 0
1 1 0 0 0 1
1 0 1 0 1 0
1 0 1 0 0 1
1 0 0 0 1 1
0 1 1 0 1 0
0 1 1 0 0 1
0 1 0 0 1 1
0 0 1 0 1 1

我编写的代码试图使这变得非常冗长和混乱,显然有更好的方法。

我正在尝试使用' counter'坐在原始阵列的位置上,并像这样移动:

1 1 1 0 1 1
c c c
c c     c
c c       c
c   c   c

等...

1 个答案:

答案 0 :(得分:2)

如果数组相对较短(应避免溢出内存),您可以使用二进制计数来构建和寻找您正在寻找的算法:

  • 假设原始数组包含N个元素
  • 将数组转换为int,将每个位置视为二进制数字;称之为set
  • 创建一个mask个数字,该数字在从0到(1 << N)-1的循环中计数。该掩码产生可以从原始
  • 中获取的所有可能的位组合
  • 通过对两者进行AND运算,生成maskset的组合:int candidate = mask & set
  • 检查candidate
  • 中设置的位数
  • 如果设置位数正好为3,则将candidate添加到列表
  • 完成循环后,您的列表将显示为int s。
  • 消除重复项,并根据需要将这些int转换为int的数组。

以下是上述算法的简单实现:

static uint FromArray(int[] data) {
    uint res = 0;
    for (int i = 0 ; i != data.Length ; i++) {
        if (data[i] == 1) {
            res |= (1U << i);
        }
    }
    return res;
}
static int[] ToArray(uint set, int size) {
    var res = new int[size];
    for (int i = 0 ; i != size ; i++) {
        if ((set & (1U << i)) != 0) {
            res[i] = 1;
        }
    }
    return res;
}
static int CountBits(uint set) {
    int res = 0;
    while (set != 0) {
        if ((set & 1) != 0) {
            res++;
        }
        set >>= 1;
    }
    return res;
}
public static void Main() {
    var example = new[]{1, 1, 1, 0, 1, 1};
    var set = FromArray(example);
    int N = example.Length;
    var res = new List<uint>();
    for (uint mask = 0 ; mask != 1U<<N ; mask++) {
        var candidate = set & mask;
        if (CountBits(candidate) == 3) {
            res.Add(candidate);
        }
    }
    foreach (var s in res.Distinct()) {
        var array = ToArray(s, N);
        Console.WriteLine(string.Join(" ", array.Select(i => i.ToString()).ToArray()));
    }
}

此代码生成以下输出:

1 1 1 0 0 0
1 1 0 0 1 0
1 0 1 0 1 0
0 1 1 0 1 0
1 1 0 0 0 1
1 0 1 0 0 1
0 1 1 0 0 1
1 0 0 0 1 1
0 1 0 0 1 1
0 0 1 0 1 1

Demo on ideone.