Kar*_*ikh 8 java arrays algorithm dynamic-programming
在Java中,我应该如何找到数组元素与特定值K的最接近(或相等)可能的总和?
例如,对于数组{19,23,41,5,40,36}和K = 44,最接近的可能总和是23 + 19 = 42.几个小时以来我一直在努力奋斗; 我对动态编程几乎一无所知.顺便说一下,数组只包含正数.
Vin*_*ele 12
您通常会使用动态编程来解决此类问题.但是,这实际上归结为保持一组可能的总和并逐个添加输入值,如下面的代码所示,并具有相同的渐近运行时间:O(n K),其中n是输入数组的大小,并且K是目标值.
但是,下面版本中的常量可能更大,但我认为代码比动态编程版本更容易理解.
public class Test {
public static void main(String[] args) {
int K = 44;
List<Integer> inputs = Arrays.asList(19,23,41,5,40,36);
int opt = 0; // optimal solution so far
Set<Integer> sums = new HashSet<>();
sums.add(opt);
// loop over all input values
for (Integer input : inputs) {
Set<Integer> newSums = new HashSet<>();
// loop over all sums so far
for (Integer sum : sums) {
int newSum = sum + input;
// ignore too big sums
if (newSum <= K) {
newSums.add(newSum);
// update optimum
if (newSum > opt) {
opt = newSum;
}
}
}
sums.addAll(newSums);
}
System.out.println(opt);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑
关于运行时间的简短说明可能是有用的,因为我刚刚声称O(n K)没有正当理由.
显然,初始化和打印结果只需要一个恒定的时间,所以我们应该分析双循环.
外循环遍历所有输入,因此它的主体执行n时间.
到目前为止,内循环遍及所有总和,理论上可以是指数.但是,我们使用上限K,因此所有值sums都在范围内[0, K].既然sums是一个集合,它至多包含K+1元素.
内循环内的所有计算都需要恒定的时间,因此总循环需要O(K).由于同样的原因,该集合newSums最多也包含K+1元素,因此addAll最终O(K)也是如此.
结束:外循环执行n次数.循环体需要O(K).因此,该算法运行于O(n K).
编辑2
根据要求如何找到导致最佳总和的元素:
而不是跟踪单个整数 - 子列表的总和 - 您还应该跟踪子列表本身.如果您创建一个新类型(没有getter/setters来保持示例简洁),这是相对简单的:
public class SubList {
public int size;
public List<Integer> subList;
public SubList() {
this(0, new ArrayList<>());
}
public SubList(int size, List<Integer> subList) {
this.size = size;
this.subList = subList;
}
}
Run Code Online (Sandbox Code Playgroud)
现在初始化变为:
SubList opt = new SubList();
Set<SubList> sums = new HashSet<>();
sums.add(opt);
Run Code Online (Sandbox Code Playgroud)
内部循环也sums需要一些小的调整:
for (Integer input : inputs) {
Set<SubList> newSums = new HashSet<>();
// loop over all sums so far
for (SubList sum : sums) {
List<Integer> newSubList = new ArrayList<>(sum.subList);
newSubList.add(input);
SubList newSum = new SubList(sum.size + input, newSubList);
// ignore too big sums
if (newSum.size <= K) {
newSums.add(newSum);
// update optimum
if (newSum.size > opt) {
opt = newSum;
}
}
}
sums.addAll(newSums);
}
Run Code Online (Sandbox Code Playgroud)