合并n个数组A1..An,每个数组Ai是{1..i}的随机子集

时间:2016-11-16 04:56:21

标签: arrays algorithm runtime bitarray coding-efficiency

我正在试图找到一种方法将标记为A1的n个数组合并到An。

每个数组Ai都是{1..i}的子集。例如,A3可以是{1}或{3}或{1,3}。请注意,每个数组都已排序。

例如n = 8, A1={}, A2={2}, A3={2,3}, A4={1,4}, A5=A6=A7={}, A8={6},将所有这些合并为{1,2,3,4,6}。

我正试图找出一种方法来做到这一点比O(n ^ 2)更快,这很明显,因为所有数组中都有O(n ^ 2)个总元素我们可以创建一个大小为n的数组,并尝试将每个元素放入一个桶中。

2 个答案:

答案 0 :(得分:0)

如果你有k个整数数组,其中包含n项的总和,那么你可以使用O(k)额外空格在O(n log k)时间内合并它们。以下是它的完成方式:

首先,创建一个名为pqitem的类型,它将数组和当前索引保存到数组中。例如:

class pqitem
    int[] A;
    int i;

然后,创建一个优先级队列(min-heap)来保存pqitem个实例。比较函数应该比较A[i],因此堆中的项目的排列使得当前项目最小的数组位于根目录。

对于每个数组,创建一个pqitem实例来保存数组。将i字段初始化为0.插入优先级队列。

现在,不断删除堆中的最低项,输出当前值,增加i,然后将项目添加回堆i < A.length。那就是:

myHeap = new heap()
for each array
    item = new pqitem(array, 0)
    myHeap.Add(item)

while (myHeap.count > 0)
    item = myHeap.pop()
    output item.A[item.i]  // output or add to new array, etc.
    ++item.i
    if (item.i < item.A.length)
        myHeap.Add(item)

在您的情况下,您希望防止重复。因此,您稍微修改合并循环以跟踪最后一项输出,并防止输出重复项。

// keep track of the previous item
prev = -1  // Initialize to a value that won't appear in the lists
while (myHeap.count > 0)
    item = myHeap.pop()
    // skip duplicates
    if (item.A[item.i] != prev)
        output item.A[item.i]  // output or add to new array, etc.
        prev = item.A[item.i]
    ++item.i
    if (item.i < item.A.length)
        myHeap.Add(item)

答案 1 :(得分:0)

您需要一个容器,该容器将包含k数组的i项,索引i和索引k

public class Node {
    int item, arrIndx, itemIndx;
    public Node(int a, int b, int c) {
        this.item = a;
        this.arrIndx = b;
        this.itemIndx = c;
    }
}

使用minHeap(优先级队列按升序排序其元素)以包含Node

首先,对于每个数组,将其第一个元素推入minHeap。 minHeap如何保存第一个n个排序元素。

现在逐个从minHeap中弹出前面元素,这是所有数组项中最小的元素并将其放入输出数组中。在弹出k数组的任何i元素期间,将k + 1数组的i元素放入队列。这样我们就可以确定,我们正在推动当前最小元素的最小元素。

继续此过程,直到从minHeap推送和弹出所有数组元素。

示例Java代码段如下所示:

public List<Integer> mergekSortedArrays(int[][] arrays) {

    List<Integer> result = new ArrayList<Integer>();

    if (arrays == null || arrays.length == 0) {
        return result;
    }

    PriorityQueue<Node> minHeap = new PriorityQueue<Node>(arrays.length,
        new Comparator<Node>() {
            public int compare(Node lhs, Node rhs) {
                return lhs.item - rhs.item;
            }
        }
    );

    // O(n log n)
    for (int i = 0; i < arrays.length; i++) {
        if (arrays[i].length > 0) {
            minHeap.offer(new Node(arrays[i][0], i, 0));
        }
    }

    Node node;

    // O((N - n)log n)
    while (!minHeap.isEmpty()) {
        node = minHeap.poll();
        result.add(node.item);
        if (node.itemIndx + 1 < arrays[node.arrIndx].length) {
            minHeap.offer(new Node(arrays[node.arrIndx][node.itemIndx + 1], node.arrIndx, node.itemIndx + 1));
        }   
    }

    return result;

}

时间复杂度为O(N log n),其中n是数组的数量,N是这些数组中所有元素的数量。