生成大列表中元素之间的总和的有序列表

时间:2019-04-02 01:18:05

标签: algorithm

我不确定该问题是否应该以溢出数学的形式发布,但是我们开始吧。

我有任意数量的带数字的有序列表(例如3)。这些列表可能足够长,以至于尝试所有值的组合在计算上都变得过于繁琐。

我需要的是从每个列表中选择一个值时获得可能的和的有序列表。由于列表可能很大,所以我只想要N个最小的和。

我考虑过的是为每次迭代降低一个列表。但是,这错过了很多情况,如果为该步骤选择了另一个列表,那本来是可能的。

一个替代方案是递归解决方案,但是它将产生许多重复的案例。

有没有已知的方法可以解决这样的问题?

2 个答案:

答案 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);
    }
}