从n个排序数组中找到k个最小数字

时间:2013-01-18 23:08:26

标签: merge sorting

我有n个不同大小的排序数组。给K我需要找到前k个最小的数字 int a [] = {10,20,30,40};
int b [] = {20,30,40};
int c [] = { - 10,0};

如果k = 1,则输出应为数组= {-10},k = 2,然后op = { - 10,0} k = 4 {-10,0,10,20,20}

我想到的想法:
1.保持最小堆,但是我是否需要扫描所有剩余阵列的所有元素? 2.维护大小为K的op数组,然后扫描所有数组的所有元素,除非我们遇到数组中大于max的元素“op”

有没有办法如果我从列开始思考?

约束:合并所有数组并找到第一个k并不好,因为数组的大小可能很大,就像单个数组中的百万个整数一样。

4 个答案:

答案 0 :(得分:1)

使用基本合并(例如在合并排序中)将在O(m)时间内运行(其中m是元素的总数),从那里你可以选择前k个元素。

编辑:关于合并的修改后:

另一个解决方案是迭代k次,并找到每个数组的第一个元素的最小值(即,如果你有数组[1,2,3,4,5],[2,4,6],和[3,4,7,8],你找到min(1,2,3)。将这个min值添加到你的解决方案数组(k个最小的整数),然后从它各自的数组中删除它。

答案 1 :(得分:1)

这可能会给你一个想法..

         List<int> new1 = new List<int>();
         List<int> testArr = new List<int>() { 10, 20, 30, 40 };
         List<int> testArr1 = new List<int>() { -10, 0 };
     int[] newArr=   testArr.Concat(testArr1).ToArray();

     var s1 = (from i in newArr
              orderby i ascending
              select i);
     foreach (var x in s1)
     {
         new1.Add(x);
     }

答案 2 :(得分:0)

一种方法是

将所有已排序的数组汇总到一个已排序的数组中,然后答案是新数组开头的k个元素。这可以通过从开始维护每个数组的索引并在将该数组中的元素推入结果数组时递增它们来实现。我已经为两个数组做了这个,你可以进一步使用它。

添加约束后编辑: 浏览所有数组,如果有任何长度&gt; k,截断到长度k(如果每个都是一个大数组,这可能是一个很好的权衡)

// Find K largest numbers in two sorted arrays
//Returns 0 on success and -1 in failure and c contains the resulting array


int k_largest(a, b, c, k) {
    int a_len = a.length;
    int b_len = b.length;
    if (a_len + b_len < k) return -1;
    int i = 0;
    int j = 0;
    int m = 0;

if(a[k] < b[0])
c=a;
else if (b[k] < a[0])
c=b;

/* (i<k) test below is to discard the rest of the elements of the arrays ,
using the sorted property of array */

    while (i < k && j < a_len && m < b_len) {
        if (a[j] < b[m]) {
            c[i] = a[j];
            i++;
            j++;
        } else {
            c[i] = b[m];
            i++;
            m++;
        }
    }

    if (i === k) {
        return 0;
    } else if (j < a_len) {
        while (i < k) {
            c[i++] = b[m++];
        }
    } else {
        while (i < k) c[i++] = a[j++];
    }
    return 0;
}

使用=结果数组和b =第三个数组再次执行此操作,依此类推

答案 3 :(得分:0)

另一种方法是将您的数组用作堆栈。您需要在每个数组中保存指向上次使用的最小值的指针,并在每次迭代时检查所有指针(示例中为3个指针)。您需要进行K次迭代才能获得K值。

以下是c#上的示例代码:

 int[] a = new int[] {10,20,30,40};
 int[] b = new int[] {20,30,40};
 int[] c = new int[] {-10,0};

 Dictionary<object, int> dic = new Dictionary<object, int>();
 dic.Add(a, 0);
 dic.Add(b, 0);
 dic.Add(c, 0);

 int K = 4;

 for (int i = 0; i < K; i++)
 {
     var min = dic.Min(s => ((int[])s.Key)[s.Value]);
     var arr = dic.First(p => ((int[])p.Key)[p.Value] == min);
     int idx = arr.Value + 1;
     dic.Remove(arr.Key);
     if (((int[])arr.Key).Length > idx)
         dic.Add(arr.Key, idx);
     Console.WriteLine(min);
 }