我不确定该问题是否应该以溢出数学的形式发布,但是我们开始吧。
我有任意数量的带数字的有序列表(例如3)。这些列表可能足够长,以至于尝试所有值的组合在计算上都变得过于繁琐。
我需要的是从每个列表中选择一个值时获得可能的和的有序列表。由于列表可能很大,所以我只想要N个最小的和。
我考虑过的是为每次迭代降低一个列表。但是,这错过了很多情况,如果为该步骤选择了另一个列表,那本来是可能的。
一个替代方案是递归解决方案,但是它将产生许多重复的案例。
有没有已知的方法可以解决这样的问题?
答案 0 :(得分:2)
让我们有K个列表。
做最小堆。
a)推入一个结构,该结构包含每个列表中元素的总和(该元素中的第一个元素)和索引列表key = Sum(L[i][0]), [ix0=0, ix1=0, ix2=0]
b)从堆中弹出最小的元素,输出key (sum)
值
c)从弹出的一个中构造K个新元素-每增加一个对应的索引并更新总和
key - L[0][ix0] + L[0][ix0 + 1], [ix0 + 1, ix1, ix2]
key - L[1][ix1] + L[1][ix1 + 1], [ix0, ix1 + 1, ix2]
same for ix2
d)将它们推入堆中
e)从b)重复直到提取出N个最小的和
答案 1 :(得分:0)
最小堆算法的Java实现,带有一个简单的测试用例: 该算法本身就是@MBo所描述的。
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
class MinHeapElement {
int sum;
List<Integer> idx;
}
public class SumFromKLists {
public static List<Integer> sumFromKLists(List<List<Integer>> lists, int N) {
List<Integer> ans = new ArrayList<>();
if(N == 0) {
return ans;
}
PriorityQueue<MinHeapElement> minPq = new PriorityQueue<>(new Comparator<MinHeapElement>() {
@Override
public int compare(MinHeapElement e1, MinHeapElement e2) {
return e1.sum - e2.sum;
}
});
MinHeapElement smallest = new MinHeapElement();
smallest.idx = new ArrayList<>();
for(int i = 0; i < lists.size(); i++) {
smallest.sum += lists.get(i).get(0);
smallest.idx.add(0);
}
minPq.add(smallest);
ans.add(smallest.sum);
while(ans.size() < N) {
MinHeapElement curr = minPq.poll();
if(ans.get(ans.size() - 1) != curr.sum) {
ans.add(curr.sum);
}
List<MinHeapElement> candidates = nextPossibleCandidates(lists, curr);
if(candidates.size() == 0) {
break;
}
minPq.addAll(candidates);
}
return ans;
}
private static List<MinHeapElement> nextPossibleCandidates(List<List<Integer>> lists, MinHeapElement minHeapElement) {
List<MinHeapElement> candidates = new ArrayList<>();
for(int i = 0; i < lists.size(); i++) {
List<Integer> currList = lists.get(i);
int newIdx = minHeapElement.idx.get(i) + 1;
while(newIdx < currList.size() && currList.get(newIdx) == currList.get(newIdx - 1)) {
newIdx++;
}
if(newIdx < currList.size()) {
MinHeapElement nextElement = new MinHeapElement();
nextElement.sum = minHeapElement.sum + currList.get(newIdx) - currList.get(minHeapElement.idx.get(i));
nextElement.idx = new ArrayList<>(minHeapElement.idx);
nextElement.idx.set(i, newIdx);
candidates.add(nextElement);
}
}
return candidates;
}
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>();
list1.add(2); list1.add(4); list1.add(7); list1.add(8);
List<Integer> list2 = new ArrayList<>();
list2.add(1); list2.add(3); list2.add(5); list2.add(8);
List<List<Integer>> lists = new ArrayList<>();
lists.add(list1); lists.add(list2);
sumFromKLists(lists, 11);
}
}