【问题标题】:Merge n arrays A1..An with each Array Ai being a random subset of {1..i}合并 n 个数组 A1..An,每个数组 Ai 是 {1..i} 的随机子集
【发布时间】:2017-03-30 04:36:12
【问题描述】:

我正在尝试找出一种将标记为 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 的数组并尝试将每个元素放入一个桶中。

【问题讨论】:

  • 它不能在少于所有数组中的总元素的情况下完成。显然,您需要读取所有数组中的每个元素。

标签: arrays algorithm runtime bitarray coding-efficiency


【解决方案1】:

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

首先,创建一个名为pqitem 的类型,它包含一个数组和数组的当前索引。例如:

class pqitem
    int[] A;
    int i;

然后,创建一个优先级队列(最小堆)来保存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)

【讨论】:

    【解决方案2】:

    您需要一个容器来保存ith 数组的kth 项、索引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中一个一个地弹出所有数组项中最小的最前面的元素,并将其放入输出数组中。在弹出ith 数组的任何kth 元素期间,将ith 数组的k + 1th 元素放入队列。这样我们可以确保,我们正在推动当前最小元素的直接最小元素。

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

    示例 Java sn-p 将如下所示:

    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 是这些数组中所有元素的数量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-05
      • 2021-10-18
      • 1970-01-01
      • 1970-01-01
      • 2011-11-19
      相关资源
      最近更新 更多