如何解决如何获取具有接近目标数组的子集的数组
我需要在数组(x 行)中找到与目标数组(1 行)最接近的子集(小于或等于)的行。
目标 | A | B |
---|---|---|
案例1 | 5 | 6 |
目标 | A | B |
---|---|---|
案例2 | 6 | 2 |
候选人 | A | B |
---|---|---|
Can1 | 1 | 2 |
Can2 | 7 | 1 |
Can3 | 1 | 0 |
Can4 | 1 | 3 |
Can5 | 2 | 2 |
Can6 | 4 | 3 |
Can7 | 0 | 1 |
case1 的结果(目标等于候选的总和):Can4 & Can6。
A 列:1 + 4 = 5
B 列:3 + 3 = 6
case2 的结果(目标大于候选的总和):Can3 & Can5
A 列:1 + 2
B 列:2 = 2
因此只应包含两列总和小于或等于的行。如果未找到最佳结果(候选的总和与目标匹配),则应包括最接近目标的行。
我找到了一个使用 oracle 递归查询的解决方案,但是当数据集较大时性能不是最优的,而且我没有找到将其转换为迭代代码的方法。
如果有人知道如何在 java 或 PL/sql 中使用迭代来实现,我将不胜感激。
解决方法
蛮力
组合问题可以在指数时间和空间中使用蛮力解决
n * 2n
方法
- 生成所有子集
- 根据某些标准仅选择有效的子集
- 如果它们都无效,则返回空结果
- 根据某些条件对有效子集进行排序
- 返回排序子集中的第一个子集
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ClosestCombination {
public static void main(String[] args) {
int[][] inputRecords = new int[][] {
{1,2},{7,1},{1,0},3},{2,{4,{0,1}
};
int[][] result = computeResult(inputRecords,new int[] {5,6});
System.out.println(Arrays.deepToString(result));
result = computeResult(inputRecords,new int[] {6,2});
System.out.println(Arrays.deepToString(result));
result = computeResult(inputRecords,new int[] {0,0});
System.out.println(Arrays.deepToString(result));
}
public static int[][] computeResult(int[][] inputRecords,int[] expected) {
List<List<int[]>> allSubsets = generateSubsets(inputRecords);
List<List<int[]>> candidates = allSubsets.stream()
.filter(subset -> isAcceptable(subset,expected))
.collect(Collectors.toList());
// if the none of the subsets are valid,then return empty result
if (candidates.size() == 0) {
return new int[0][0];
}
// reverse sort
candidates.sort((a,b) -> {
int v1 = normalize(a);
int v2 = normalize(b);
// if the values are same,then pick smaller size
return v1 == v2 ? a.size() - b.size() : v2 - v1;
});
List<int[]> result = candidates.get(0);
return result.toArray(new int[0][0]);
}
// add custom value generation as per business meaning of "closest"
private static int normalize(List<int[]> subset) {
return subset.stream().mapToInt(a -> a[0] + a[1]).sum();
}
// add custom validation check as per business meaning of "closest"
private static boolean isAcceptable(List<int[]> subset,int[] expected) {
int valueA = subset.stream().mapToInt(a -> a[0]).sum();
int valueB = subset.stream().mapToInt(a -> a[1]).sum();
return valueA <= expected[0] && valueB <= expected[1];
}
// generates all possible subsets (does not include the empty set)
private static List<List<int[]>> generateSubsets(int[][] inputRecords) {
List<List<int[]>> all = new ArrayList<>(); // holds all subsets
for (int[] input : inputRecords) {
// subsets generated by including the current input element
List<List<int[]>> includedSubsets = new ArrayList<>();
// include the current element alone
List<int[]> current = new ArrayList<>();
current.add(input);
includedSubsets.add(current);
// clone all previously computed subsets and add current element to the clones
for (List<int[]> subset : all) {
List<int[]> withCurrentInput = new ArrayList<>(subset);
withCurrentInput.add(input);
includedSubsets.add(withCurrentInput);
}
// add subsets generated in current iteratiion to result
all.addAll(includedSubsets);
}
return all;
}
}
TODO:尚未添加DP解决方案以优化时间和空间
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。