gpt4 book ai didi

java - 所有可能的对

转载 作者:行者123 更新时间:2023-11-30 09:16:19 26 4
gpt4 key购买 nike

给定一组数字,从 1 到 n,我需要对所有可能对的所有集合建模。

换句话说,一组开奖由所有号码组成。数字是成对的。如果计数是奇数 - 允许一个条目和一个数字(实际上这是必需的)。集合需要是唯一的,即对 [1,2] 与 [2,1] 相同(编辑:和解决方案:[1,2] [3,4] 与 [3,4] [1, 2]).

例如,当n等于5时,可以创建如下集合:

[1,2] [3,4] [5]
[1,2] [3,5] [4]
[1,2] [4,5] [3]
[1,3] [2,4] [5]
[1,3] [2,5] [4]
[1,3] [4,5] [2]
....

我几乎可以对解决方案进行建模,但是唯一性约束对我来说很难实现。

此外 - 我觉得我的解决方案缺乏性能。我现在问题空间很大,但对我来说,即使 n=12 计算也需要 5 分钟以上。

public void compute(HashSet<Number> numbers, ArrayList<Pair> pairs) {
if (numbers.size() <= 1) {
print(pairs);
} else {
for (Number number1 : numbers) {
for (Number number2 : numbers) {
if (number1 != number2) {
Set<Number> possibleNumbers = new HashSet<Number>(numbers);
List<Pair> allPairs = new ArrayList<Pair>(pairs);

possibleNumbers.remove(number1);
possibleNumbers.remove(number2);
allPairs.add(new Pair(number1, number2));

compute(possibleNumbers, allPairs);
}
}
}
}
}

compute(numbers, new ArrayList<Pair>());

对于 n=3,我得到了双倍的解决方案:

[0 1] [2] 
[0 2] [1]
[1 0] [2]
[1 2] [0]
[2 0] [1]
[2 1] [0]

那么:我应该如何实现这个问题来摆脱重复。如何改进实现以加快处理速度?

最佳答案

你可以做两件事:

1) 坏处:

您可以继续当前的方法,但是在添加对时,您需要:

a) 确保每一对总是以某种顺序排列,例如总是[smallerNumber, biggerNumber]

b) 保持 allPairs 列表排序

然后当您完成计算时,删除重复项将变得微不足道。这是一个糟糕的方法,因为它会非常慢。

2) 您可以使用不同的算法:

我将在这里做出 2 个假设:

  • 这是一个集合,所以我们没有重复
  • 它们可以很容易地排序,即对于 1 到 5,我们知道它将是 1、2、3、4、5(但它也应该适用于情况 1、3、5、6)

基本上我们会有一个递归算法(就像你的)。输入将是“数字”-> 有序(升序)列表,输出将是一组成对的列表。让我们再次调用此方法 compute(List numbers)。

-> 输入列表“numbers”有 1 个或 2 个元素时的基本情况。在这种情况下,返回一个包含一个列表的集合,该列表包含一个包含该 1 元素或两者的“对”。 IE。 numbers = [2,3] 或 numbers = [2] 然后你返回一个包含一个列表的集合,其中包含一个“对”(2,3)或(3)。

-> 对于包含第一个元素的列表“数字”中的每一对数字(即在第一级递归中数字 = [1,2,3,4,5] 它将是 [1,2] , [1,3], [1,4], [1,5], [1,6]) 调用 Set<List<Pair> result = compute(numbers.minus(currentPair)) .迭代该集合并在每个元素的开头添加当前对。

例子:

result = empty
numbers = [1,2,3,4,5]
first = (1,2), compute([3,4,5])
first = (3,4), compute([5])
return (5)
result = result + [(3,4)(5)]
first = (3,5) compute([4])
return (4)
result = result + [(3,5),(4)] (a this point result is [ [(3,4)(5)], [(3,5)(4)] ]
add (1,2) to each list in result which gives us [ [(1,2)(3,4)(5)], [(1,2)(3,5)(4)] ]

first = (1,3), compute([2,4,5])
first = (2,4), compute([5])
return (5)
result = result + [(2,4)(5)]
first = (2,5) compute([4])
return (4)
result = result + [(2,5),(4)] (a this point result is [ [(2,4)(5)], [(2,5)(4)] ]
add (1,3) to each list in result which gives us [ [(1,3)(2,4)(5)], [(1,3)(2,5)(4)] ]
at this point we have:
[ [(1,2)(3,4)(5)], [(1,2)(3,5)(4)], [(1,3)(2,4)(5)], [(1,3)(2,5)(4)] ]

对 (1,4)、(1,5) 和 (1,6) 继续此操作,您就完成了。您不必从 (2,3) 开始执行计算 ([1,4,5]),因为这会导致重复。

这个算法应该也适用于偶数集。

还没有测试过,没有证明,但看起来不错,应该很容易编码,如果它有效,那么它应该非常快,因为它只会进行必要的计算。

在代码中(我在这里写了整个代码,所以它完全没有经过测试,可能包含编译和逻辑错误!):

public Set<List<Pair>> compute(List<Integer> numbers) {
if(numbers.size() < 3) {
// Base case
List<Pair> list = new ArrayList<>();
list.add(new Pair(numbers));
Set<List<Pair>> result = new HashSet<>();
result.add(list);
return result;
} else {
Set<List<Pair>> result = new HashSet<ArrayList<>>();
// We take each pair that contains the 1st element
for(int i = 1; i < numbers.size(); i++) {
Pair first = new Pair(numbers.get(0), numbers.get(i));
// This is the input for next level of recursion
// Our numbers list w/o the current pair
List<Integers> nextStep = new ArrayList<>(numbers);
nextStep.remove(i);
nextStep.remove(0);
Set<List<Pair>> intermediate = null;
if(nextStep.size() % 2 == 0) {
intermediate = compute(nextStep);
} else {
intermediate = compute(numbers).addAll( firstElementSingle(numbers) ),compute( nextStep );
}
for(List<Pair> list : intermediate ) {
// We add the current pair at the beginning
list.add(0, first);
}
result.addAll(intermediate);
}
return result;
}
}

如果我错过了什么,我自己也很好奇,所以我期待您的反馈:-)

@编辑:

正如@yusuf 所指出的,当输入是奇数列表时,这会遗漏一些排列。它会错过所有 [1] 是单个元素的结果。

但是如果我在这种情况下没有弄错(奇数个元素),这应该可行:

compute(numbers).addAll( firstElementSingle(numbers) )

firstElementSingle 在哪里:

private Set<List<Integer>> firstElementSingle(List<Integer> numbers) {
Set<List<Integer>> result compute(numbers.subList(1,numbers.size()) );
for(List<Integer> list : result) {
list.add(numbers.get(0));
}
return result;
}

而且仍然只会产生必要的结果。

关于java - 所有可能的对,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19466600/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com