我正在使用我创建的链接列表,其中包含一组数字作为数据。我需要找到一种方法来测试这个列表的每个可能的两组分区,为此,我需要将列表分成每个可能的两组组合。订单并不重要,会有重复。
For instance, for a list of numbers {1 4 3 1}, the possible splits are
{1} and {4, 3, 1}
{4} and {1, 3, 1}
{3} and {1, 4, 1}
{1} and {1, 4, 3}
{1, 4} and {3, 1}
{1, 3} and {4, 1}
{1, 1} and {4, 3}
4个数字的列表并不困难,但随着列表变大,事情变得更加复杂,我看到模式时遇到了麻烦。任何人都可以帮我找到一个算法吗?
编辑:
抱歉,我没有看到这个问题。这是我到目前为止所尝试的。我的循环结构是错误的。当我在尝试使用常规数组后弄清楚我在做什么时,我会扩展算法以适合我的链表。
public class TwoSubsets
{
public static void main(String[] args)
{
int[] list = {1, 3, 5, 7, 8};
int places = 1;
int[] subsetA = new int[10];
int[] subsetB = new int[10];
for (int i = 0; i < list.length; i++)
{
subsetA[i] = list[i];
for (int current = 0; current < (5 - i ); current++)
{
subsetB[current] = list[places];
places++;
}
System.out.print("subsetA = ");
for (int j = 0; j < subsetA.length; j++)
{
System.out.print(subsetA[j] + " ");
}
System.out.println();
System.out.print("subsetB = ");
for (int k = 0; k < subsetB.length; k++)
{
System.out.print(subsetB[k] + " ");
}
}
}
}
答案 0 :(得分:1)
所以你正在寻找给定集合的所有(适当的)子集,除了互补的子集。如果您的列表包含n个元素,则您将拥有2 ^ n个子集。但是既然你不想要空子集,并且想要用(B,A)识别分区(A,B),你就得到2 ^(n-1)-1个分区。
要枚举它们,你可以识别一个带有n个数字的二进制数的分区,其中位置k中的数字0表示列表的第k个元素位于分区的第一个集合中,1表示它位于第二个。您想要识别具有互补性的数字(与另一个交换集合),并且您想要排除0(空子集)。
所以你可以使用按位运算。 XOR运算符为您提供补充细分。所以类似下面的内容应该有效:
int m = (1<<n)-1; // where n is the number of elements, m=111111...11 in binary
for (int i=0;i<m-1;++i) {
if (i>(m^i)) continue; // this was already considered with 0 and 1 exchanged
// here the binary digits of i represent the partition
for (int j=0;j<n;++j) {
if ((1<<j) & i) {
// the j-th element of the list goes into the second set of the partition
} else {
// the j-th element of the list goes into the first set of the partition
}
}
}
答案 1 :(得分:1)
代码:
public static void main(String[] args) {
for(String element : findSplits(list)) {
System.out.println(element);
}
}
static ArrayList<String> findSplits(ArrayList<Integer> set) {
ArrayList<String> output = new ArrayList();
ArrayList<Integer> first = new ArrayList(), second = new ArrayList();
String bitString;
int bits = (int) Math.pow(2, set.size());
while (bits-- > 0) {
bitString = String.format("%" + set.size() + "s", Integer.toBinaryString(bits)).replace(' ', '0');
for (int i = 0; i < set.size(); i++) {
if (bitString.substring(i, i+1).equals("0")) {
first.add(set.get(i));
} else {
second.add(set.get(i));
}
}
if (first.size() < set.size() && second.size() < set.size()) {
if (!output.contains(first + " " + second) && !output.contains(second + " " + first)) {
output.add(first + " " + second);
}
}
first.clear();
second.clear();
}
return output;
}
输出:
[1] [1, 4, 3]
[3] [1, 4, 1]
[3, 1] [1, 4]
[4] [1, 3, 1]
[4, 1] [1, 3]
[4, 3] [1, 1]
[4, 3, 1] [1]
这是否符合您的要求?如果没有,请告诉我,我会根据需要进行调整或添加评论。
答案 2 :(得分:0)
使用链表来存储子集实际上非常理想 - 代码将比使用数组更容易。
编写一个构建子集的递归函数。它将采用以下参数:
以下是Ruby中粗略的代码草图:
# 'input', and 'output' are linked-list nodes
# we'll assume they have 'value' and 'next' attributes
# we'll further assume that a new node can be allocated with Node.new(value,next)
# the lists are null-terminated
def build_subsets(input, output, results)
if input.nil?
results << output
else
item = input.value
input = input.next
build_subsets(input, Node.new(item, output), results)
build_subsets(input, output, results)
end
end
调用类似这样的东西:
results = []
build_subsets(list, nil, results)
之后,所有子集都将在results
中。我知道你需要Java翻译,但这应该很容易翻译成Java。我只是告诉你代码如何工作的想法。