这是0-1背包问题的一个实现。问题陈述是这样的,
您将看到两个数组,一个包含一组项目的权重,另一个包含各个权重的值。我们为你提供了最大重量。在不超过最大权重的约束下,确定通过选择或不选择项目集可以获得的最大值。值和权重列表将始终具有相同的大小。
这是我的解决方案,它通常工作得很好(不适用于边缘情况)。
public static int getCombination(int[] weights, int[] values, int maxWeight){
int[][] memo = new int[weights.length][maxWeight + 1];
for (int i = 0; i < memo.length; i++) {
for(int j=0; j < memo[i].length; j++){
if(j == 0){
memo[i][j] = 0;
}else if(weights[i] > j){
if(i == 0) memo[i][j] = 0;
else memo[i][j] = memo[i-1][j];
}else{
if(i == 0){
memo[i][j] = values[i];
}
else{
memo[i][j] = Integer.max((values[i] + memo[i-1][j- weights[i]]), memo[i-1][j]);
}
}
}
}
return memo[weights.length -1][maxWeight];
}
现在,我想使用Java8流和lambda以声明式的方式重写这个完整的逻辑。有人能帮我一下吗。
发布于 2017-05-16 17:11:29
由于您的基于for循环的解决方案完全没问题,如果您只将for循环转换为forEach streams,那么streams在这里不会增加太多价值。
如果使用IntStream
和toArray
方法,您可以从使用streams中获得更多,因为您可以专注于根据行和列索引计算值,而不必关心将其填充到数组中。
int[][] memo = IntStream.range(0, rows)
.mapToObj(r -> IntStream.range(0, cols)
.map(c -> computeValue(r, c))
.toArray())
.toArray(int[rows][cols]::new);
在这里,我们为每一行创建一个数组,然后在最后将这些数组放入2D数组中。如您所见,toArray()
方法负责填充数组。
实际上,现在我研究了您的方法来更仔细地计算值,我意识到在这种情况下使用streams可能很困难,即使不是不可能。问题在于,您需要以前的列和行中的值来计算当前值。这在我的解决方案中是不可能的,因为我们只在最后创建数组。更具体地说,我的方法是无状态的,即你不记得以前迭代的结果。
您可以看看是否可以使用Stream.reduce()
来实现您的目标。
发布于 2017-05-16 05:11:32
顺便说一句,你的方法很好。如果您不想将其并行化,那么您可以继续。
下面是在数组中创建索引的可能起点:
int rows = 3;
int cols = 4;
int[][] memo = new int[rows][cols];
IntStream.range(0, rows * cols).forEach(n -> {
int i = n / cols;
int j = n % cols;
System.out.println("(" + i + "," + j + ")");
});
https://stackoverflow.com/questions/43988639
复制相似问题