洗牌ArrayList直到满足条件(Java)
首先,我不是以英语为母语的人,所以请原谅我的一些错误 我想洗牌一个ArrayList(这没问题),但洗牌后列表必须满足某些条件。 我的第一种方法是创建if语句,并在每次它们为真时进行洗牌。但有这么多的条件,我不知道如何正确地连接它们 例如: 我有一个包含以下整数的ArrayList:洗牌ArrayList直到满足条件(Java),java,arraylist,shuffle,multiple-conditions,Java,Arraylist,Shuffle,Multiple Conditions,首先,我不是以英语为母语的人,所以请原谅我的一些错误 我想洗牌一个ArrayList(这没问题),但洗牌后列表必须满足某些条件。 我的第一种方法是创建if语句,并在每次它们为真时进行洗牌。但有这么多的条件,我不知道如何正确地连接它们 例如: 我有一个包含以下整数的ArrayList: 0, 1, 2, 3, 4, 5, 6 洗牌后的条件: 偶数不能跟在偶数后面,除非它是6 6可以放在任何地方 也就是说,0后面不能跟1,所以下一个可能的数字是 三、五、六岁。( 例如,1.1后面只能跟0、4或6
0, 1, 2, 3, 4, 5, 6
洗牌后的条件:
- 偶数不能跟在偶数后面,除非它是6
- 6可以放在任何地方
- 也就是说,0后面不能跟1,所以下一个可能的数字是 三、五、六岁。(
- 例如,1.1后面只能跟0、4或6
- 列表必须以偶数开头(最好不要以6开头,但这并不重要)
- 偶数不能跟在另一个偶数后面
- 数字后面不能跟最近的数字(1后面不能跟2,只能跟0、4或6)
- 如前所述:6可以放在任何地方
- 无序列表可以是这样的:0、3、6、5、2、1、4
如果我想创建多个If语句,我的主要问题是找出有效链接它们的正确方法(以便考虑每个If语句)。洗牌方法不好,原因有两个:
- 我们得到一组数字(可以用列表表示)
- 我们需要一个布尔函数
,如果给定的数字可能会扩展到目前为止的结果列表,则该函数将返回true。(您给出的规则允许使用一个更简单的函数,该函数包含两个数字,但对于更复杂的条件,如canFollow
5后面可以跟8,只有在前面没有6的情况下,更通用的函数才起作用。)
- 一旦你有了这个,你就可以构建一个解决方案:从一个空列表开始。当给定的集合不是空的时,从中提取一个元素,并检查它是否可以跟随结果。如果是这样,重复操作直到给定的集合为空,这样你就有了一个解决方案。否则,尝试下一个数字:
List<Int> brute(List<Int> result, List <Int> given) {
if (given is empty) return result;
foreach i in given
if i can follow result
r = brute(result + i, given - i)
if r != null return r
return null
}
solution = brute([], [1,2,3,4,5,6])
列表暴力(列表结果,列表给定){
如果(给定为空)返回结果;
每一个我都在给予
如果我能跟踪结果
r=暴力(结果+i,给定-i)
如果r!=null返回r
返回空
}
解决方案=暴力([],[1,2,3,4,5,6])
(请注意,result+i是result的缩写,后面附加了i,并给出了-i,但没有给出i,但请确保在构造此结果时不会破坏原始结果和给定值。)
如果您需要所有解决方案,可以通过将有效结果添加到一些开始为空的列表中来轻松改变这一点。假设您有一个要求,即所有可能的结果都具有同等的可能性,那么唯一简单的方法就是使用暴力创建所有组合,然后从中随机选择。所有组合都是
7!==7*6*5*4*3*2*1==5040
组合其实并不多。但对于更多的组合,我不推荐这种方法
List<int[]> valid = new ArrayList<>(5040);
recursiveBuild(valid, new int[] {}, new int[] { 0,1,2,3,4,5,6));
现在使用这些规则检查有效性:
boolean isValid(int[] arr, int index) {
for (CheckCondition c: conditions)
if (!c.passesCondition(arr.length-1, arr)
return false;
return true;
}
boolean isValid(int[] arr) {
for (int i=0;i<arr.length;i++) {
if (!isValid(arr, i);
return false;
}
return true;
}
布尔值有效(int[]arr,int索引){
用于(检查条件c:条件)
如果(!c.passesCondition(arr.length-1,arr)
返回false;
返回true;
}
布尔值无效(int[]arr){
对于(int i=0;i)您的方法是错误的-可能需要大量的重试才能通过随机洗牌列表达到所需的状态。您应该想出一个算法来强制执行所需的洗牌,例如,分别洗牌奇数和偶数,然后合并它们。@Alex:我尝试了几个if语句,如:if(rng.get)(i) .equals(0)和&rng.get(i+1).equals(1)){Collections.shuffle(rng);}我想你可以强制所有组合,并在违反约束时修剪搜索树,这样行吗?否则这个问题更适合于说函数式编程。你能明确列出你的所有条件吗?顺便说一句,你的英语真的很好。注意,我甚至没有运行过这段代码gh是一个语法检查器,因此几乎肯定需要一些戳/测试等:)注意!这是一个好主意!谢谢:)我将尝试实现它。我刚刚用您的更新列表更新了它criteria@TimB因为元素越多,排列的数量就越高,所以最好在添加一个数字之前或之后立即检查它是否有效。顺便说一句,你的recursiveBuild
方法不是递归的,不知道这是否有效。你是对的,我错过了实际的递归调用。现在添加它。另一方面,我同意在每次传递时检查有效性会更有效,我也要添加这一点。
interface CheckCondition {
boolean passesCondition(int index, int[] arr);
}
CheckCondition[] conditions = new CheckCondition[] {
new CheckCondition() {
@override
public boolean passesCondition(int index, int[] arr) {
// The list has to start with an even number
return index!=0 || arr[index]%2==0;
}
},
new CheckCondition() {
@override
public boolean passesCondition(int index, int[] arr) {
// an even number can't follow an even number, unless it's 6.
return index==0 || arr[index]==6 || arr[index]%2==1 || arr[index-1]%2==1;
}
},
new CheckCondition() {
@override
public boolean passesCondition(int index, int[] arr) {
// a number can't be followed by the next closest one unless its 6
return index==0 || arr[index]!=arr[index-1]-1 || arr[index]==6;
}
},
};
boolean isValid(int[] arr, int index) {
for (CheckCondition c: conditions)
if (!c.passesCondition(arr.length-1, arr)
return false;
return true;
}
boolean isValid(int[] arr) {
for (int i=0;i<arr.length;i++) {
if (!isValid(arr, i);
return false;
}
return true;
}