有20个数组,每个数组有500个元素,升序排列,现在在这20*500个数中找出排名前500的数。求时间复杂度?

      有20个数组,每个数组有500个元素,升序排列,现在在这20*500个数中找出排名前500的数。求时间复杂度?

      注意:调堆的时间复杂度为logN, 建堆的时间复杂度是O(N)。

    1. 直接暴力求解,将20个数组合并,然后排序,取出500个数

    2. 使用归并。 对于排好序的 序列,我们要注意使用归并。 
      先将第1个和第2个归并,得到500个数据(注意,我们不是归并得到100个数)。然后再加结果和第3个归并,得到500个数据,再与第4个归并,等等。

    3. 网上的方法,就是堆。保持一个20的堆,然后先将每个数组的第1个数入堆。

      20个元素的堆一直保持容量为20个,20个数组的最小元素可以将20个数组的第0个元素入堆,最小堆的性质,顶点为最小值。这时候得到了500个结果里的第0个结果。然后再把下一个元素入20个元素的堆,堆插入的时候会保持性质不变,最小元素依然在顶点。再取出20个元素的顶点,得到500个结果里的第1个结果。

      假设 [1,3,4,5,6] [2,3,4,5,6] [3,4,5,6,7] 
      最小的是比较 1 2 3 得到1 
      第2小的是将刚才的1替换为后面的元素3 再加上刚才的元素2 3,得到2

      注意这儿需要保持数来自于哪个数组,以及其在数组里的位置

// 方法3,保持一个最小堆,这个堆存放来自20个数组的最小数
        // 建立堆的时间复杂度为O(20),
        // 每次取出一个数,然后将该数所在的数组的后面一个数入堆
        // 重复上面步骤,取出500个数
        // 注意建堆的时候需要保持 数来自哪个数组,用一个内部类实现
        // 复杂度是 O(20)+500 * log(20)
        Integer[] result3 = new Integer[500];
        MinHeap<DataWithSource> heap = new MinHeap<DataWithSource>();
        for (int i = 0; i < rowSize; i++) {
            // 记录下来源那个数组,以及在数组中的 index
            DataWithSource d = new DataWithSource(data[i][0], i, 0);
            heap.add(d);
        }

        int num = 0;
        while (num < columnSize) {
            // 删除顶点元素
            DataWithSource d = heap.removeTop();
            result3[num++] = d.getValue();

            // 将 value 置为该数原数组里的下一个数
            d.setValue(data[d.getComeFrom()][d.getIndex() + 1]);

            // 将其在数组中的 index +1
            d.setIndex(d.getIndex() + 1);
            heap.add(d);
        }