【面试题30】最小的k个数

【题目描述】

输入n个整数,找出其中最小的k个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。

【解决方案】

测试用例:

1. 功能测试(输入数组中有相同的数字,输入数组中没有相同的数字);

2. 边界值测试(输入的k等于1或者等于数组的长度);

3. 特殊情况测试(k小于1,k大于数组的长度,指向数组的指针为null);

解法一:基于Partition函数来解决

优点:时间复杂度为o(n);

缺点:会修改原数组;不适用于数据量较大的查找(例如,数组一次性加载不到内存中);

我的代码实现,仅供参考:

 1         public static void GetLeastNums(int[] arr, int k)
 2         {
 3             if (arr == null || arr.Length < k || k <= 0)
 4                 return;
 5 
 6             int start = 0;
 7             int end = arr.Length - 1;
 8             int index = Partition(arr, start, end);
 9 
10             while (k - 1 != index)
11             {
12                 if (index > k - 1)
13                 {
14                     end = index - 1;
15                     index = Partition(arr, start, end);
16                 }
17                 else
18                 {
19                     start = index + 1;
20                     index = Partition(arr, start, end);
21                 }
22             }
23 
24             for (int i = 0; i < k; i++)
25             {
26                 Console.Write(arr[i]);
27             }
28         }
29 
30         public static int Partition(int[] arr, int start, int end)
31         {
32             int temp = arr[start];
33 
34             while (start < end)
35             {
36                 while (start < end && arr[end] >= temp)
37                     end--;
38                 arr[start] = arr[end];
39 
40                 while (start < end && arr[start] <= temp)
41                     start++;
42                 arr[end] = arr[start];
43             }
44 
45             arr[start] = temp;
46 
47             return start;
48         }

解法二:利用大根堆的特性,在堆中保存前k个小的数,遍历数组,满足则替换

优点:不需要修改原数组;适合数据量大,所求k较小的情况;

缺点:时间复杂度为O(nlogk);

我的代码实现,仅供参考:

 1         public static void GetLeastNums(int[] arr, int k)
 2         {
 3             if (arr == null || arr.Length < k || k <= 0)
 4                 return;
 5 
 6             int[] arrK = new int[k];
 7 
 8             //为大根堆数组赋值
 9             for (int i = 0; i < k; i++)
10             {
11                 arrK[i] = arr[i];
12             }
13 
14             //构建大根堆
15             for (int j = arrK.Length / 2 - 1; j >= 0; j--)
16             {
17                 MaxHeapify(arrK, j);
18             }
19 
20             for (int i = k; i < arr.Length; i++)
21             {
22                 //如果比大根堆的最大值还要大,则覆盖最大值,然后调整大根堆
23                 if (arrK[0] > arr[i])
24                 {
25                     arrK[0] = arr[i];
26                     MaxHeapify(arrK, 0);
27                 }
28             }
29 
30             foreach (int num in arrK)
31                 Console.Write(num);
32         }
33 
34         /// <summary>
35         /// 调整大根堆
36         /// </summary>
37         /// <param name="arr"></param>
38         public static void MaxHeapify(int[] arr, int currentIndex)
39         {
40             int left = currentIndex * 2 + 1;
41             int right = currentIndex * 2 + 2;
42             int large = currentIndex;
43 
44             if (left < arr.Length && arr[left] > arr[large])
45             {
46                 large = left;
47             }
48 
49             if (right < arr.Length && arr[right] > arr[large])
50             {
51                 large = right;
52             }
53 
54             if (large != currentIndex)
55             {
56                 Swap(arr, large, currentIndex);
57 
58                 MaxHeapify(arr, large);
59             }
60         }
61 
62         public static void Swap(int[] arr, int indexA, int indexB)
63         {
64             int temp = arr[indexA];
65             arr[indexA] = arr[indexB];
66             arr[indexB] = temp;
67         }
原文地址:https://www.cnblogs.com/HuoAA/p/4813480.html