题目:给定一个数组A,找出数组中前K个最小的数
分析:最直观的想法应该是排序,排完序之后输出前K个数就ok了。排序可以用平均复杂度为O(n * logn)的快速排序。但题目并没有要求输出的前K个最小数有序,既然如此,就没有必要为所有元素排序。我们可以采用其他方法。 即:
- 取A中前K个数,假设这就是数组A中最小的K个数。
- 对选出的K个数取最大值max_tmp。
- 遍历数组A中剩余的数,如果A[i] < max_tmp 则交换max_tmp,A[i]的位置,然后重复步骤2;如果A[i] > max_tmp,则不做任何处理。
- 输出数组A中前K个元素即为最小的K个数。
每次遍历更新或不更新数组的时间复杂度为O(K)或者O(0),所以最终时间复杂度为n * O(K);
代码实现如下:1234567891011121314151617181920212223242526272829303132333435363738function find($arr,$k){$len = count($arr);if($len <= $k){return $arr;}$i = findMinItem($arr,$k);for($index = $k; $index < $len; $index++){if($arr[$index] < $arr[$i]){$tmp = $arr[$index];$arr[$index] = $arr[$i];$arr[$i] = $tmp;$i = findMinItem($arr,$k);}}return $arr;}function findMinItem($arr,$end){$index = 0;$minTmp = $arr[0];for($i = 0; $i < $end; $i++){if($arr[$i] > $minTmp){$index = $i;}}return $index;}$arr = [9,8,7,6,5,4,3,2,1];$ret = find($arr,2);print_r($ret);
除此之外还有其他方法,类似与使用堆排序来构建临时数组,由于堆中的数据是已经排好序的,每次取数组A中的元素与堆顶元素做比较,如果小于堆顶元素则替换堆顶元素,并重新构建堆;否则不更新堆。