有一个 ArrayList 为x
unique Integers
,我需要将它们随机分配y
数组列表z
尺寸。请记住:
-
x y z
是变量值。
- 结果数组中的数字不能重复。
- 结果列表不能包含相同的数字! (订购它们必须不同)
- 如果计算结果数组中的出现次数,则原始数组中每个数字的使用次数必须尽可能与其他数字相同。
- 必须使用原数组中的所有数字,不能使用任何数字
它们不能不被使用。
- 如果可能的话,必须在 Java 7 中工作。不是 100% 强制,但是...
- 所得组合将用于类似于彩票的用途,因此它们不能太连续并且必须非常随机。它们还将按从最小到最大的顺序排列。
- 最初,我尝试生成所有可能的组合,目的是获得所需的数量,但这是不可行的,因为如果您选择高值,例如 11 的组合中的 40 个数字,则有数百万个数字,并且 CPU 会卡在计算很长时间,所以我尝试开发一种更简单的算法,而不计算所有组合(我在下面发布代码)。
一个示例是这样的,当您有一个包含 8 个元素的数组的原点并且想要输出 3 个大小为 6 的数组时:
原始数组列表:[1,2,3,4,5,6,7,8]
结果输出: [7, 5, 3, 6, 4, 8], [7, 5, 1, 8, 2, 3], [8, 1, 2, 3, 4, 6]
我开发了一种算法,在评论中进行了解释。首先,我创建了一个包含总位置的数组,并计算每个数字必须重复多少次才能填充输出数组。然后我用重复必要次数的每个数字填充数组,如果数组未满(因为当我除以得到placesByNumber
我四舍五入为整数)我用原始数字集中的随机数填充它。之后,我对数字进行洗牌,最后,我填充结果数组,并记住我不能在每个结果数组中重复数字。
问题就在这里,有时,我遇到最后一个数组没有完全填满的情况,因为洗牌的最后一个数字numbersGroup
变量包含在最后一个数组中。
这是一个失败的例子:
原始数组列表:[1,2,3,4,5,6,7,8]
打乱一组数字以填充结果数组:
[8、2、4、4、5、7、2、3、8、2、1、5、7、1、6、3、6、1]
结果数组:(第三个没有 6 个元素,因为 6 和 1 是
包含在其中)
[[8,2,4,5,7,3],[4,2,8,1,5,7],[2,1,6,3]]
我发现了一些非常丑陋的方法来解决它,但效率非常低,我正在尝试找到一种更好、更有效的算法来实现这一目标。
这是我的源代码:
public static List<List<Integer>> getOptimizedCombinations(List<Integer> numbers, int numbersPerCombination, int desiredCombinations){
List<List<Integer>> result = new ArrayList<>();
//calculate total places and how many places correspond to each number.
int totalPlaces = numbersPerCombination * desiredCombinations;
int placesByNumber = totalPlaces / numbers.size();
//instantiating array with the total number of places
Integer[] numbersGroup = new Integer[totalPlaces];
//filling the array with the numbers, now we know how many times a number must be inside the array,
//so we put the numbers. First we do it in order, later we will shuffle the array.
int pos = 0;
for (int n : numbers) {
for (int i=0; i<placesByNumber; i++) {
numbersGroup[pos] = n;
pos++;
}
}
//if there are places for fill, we fill it with random numbers. This can be possible because when we divide the total places between the
//numbers size, it can give a decimal as a result, and we round it to lower binary number without decimals, so it is possible to
//have non filled places.
if (pos<totalPlaces) {
while(pos<totalPlaces) {
numbersGroup[pos] = numbers.get(getRandom(0, numbers.size()));
pos++;
}
}
shuffleArray(numbersGroup);
//we instantiate the arraylists
for (int i=0; i<desiredCombinations; i++) {
result.add(new ArrayList<Integer>());
}
//filling the arraylists with the suffled numbers
for (int i=0; i<numbersGroup.length; i++) {
for (int j=0; j<result.size(); j++) {
//if the combination doesn't have the number and the combination is not full, we add the number
if (!result.get(j).contains(numbersGroup[i]) && result.get(j).size()<numbersPerCombination) {
result.get(j).add(numbersGroup[i]);
break;
}
}
}
return result;
}
static void shuffleArray(Integer[] ar){
Random rnd = new Random();
for (int i = ar.length - 1; i > 0; i--)
{
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
public static int getRandom(int min, int max) {
return (int)(Math.random() * max + min);
}
这就是这样的:
ArrayList<Integer> numbers = new ArrayList<Integer>() {{
add(1);
add(2);
add(3);
add(4);
add(5);
add(6);
add(7);
add(8);
}};
getOptimizedCombinations(numbers, 6, 3);