题目描述 输入整数数组 arr
,找出其中最小的 k
个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
1 2 输入:arr = [3,2,1], k = 2 输出:[1,2] 或者 [2,1]
示例 2:
1 2 输入:arr = [0,1,2,1], k = 1 输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
题目链接 Leetcode
题目解答 解法一 按照题目要求,最直观的处理方式就是先排序,然后取排序后数组的前k个元素组成新数组返回即可。
时间复杂度:$O(n\log{}n)$ 空间复杂度:$O(\log{}n)$
1 2 3 4 5 6 7 8 9 10 class Solution { public int [] getLeastNumbers(int [] arr, int k) { Arrays.sort(arr); int [] res = new int [k]; for (int i = 0 ; i < k; i++) { res[i] = arr[i]; } return res; } }
执行用时:7 ms, 在所有 Java 提交中击败了72.51%的用户 内存消耗:39.7 MB, 在所有 Java 提交中击败了68.57%的用户
解法二 题目要求找出最小的k个元素,我们可以使用一个大根堆实时维护数组中前k小的元素,初始化堆的时候,先直接把数组前k个元素加入堆中,从第k+1个元素开始,把元素值与堆顶值做比较,如果比堆顶值小,就把堆顶元素弹出,把数组元素加入到堆中。数组遍历结束的时候,用堆中的元素组成的新数据就是所需结果。
时间复杂度:$O(n\log{}k)$ 空间复杂度:$O(\log{}k)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public int [] getLeastNumbers(int [] arr, int k) { int [] res = new int [k]; if (k == 0 ) { return res; } PriorityQueue<Integer> queue = new PriorityQueue<>(((o1, o2) -> o2 - o1)); for (int i = 0 ; i < k; i++) { queue.offer(arr[i]); } for (int i = k; i < arr.length; i++) { if (queue.peek() > arr[i]) { queue.poll(); queue.offer(arr[i]); } } for (int i = 0 ; i < k; i++) { res[i] = queue.poll(); } return res; } }
执行用时:20 ms, 在所有 Java 提交中击败了33.19%的用户 内存消耗:39.5 MB, 在所有 Java 提交中击败了88.20%的用户
解法三 使用分治递归把大问题划分为子问题求解,借鉴快速排序的划分函数,我们可以选取一个中间值target
把数组划分为两部分,同时调整两部分的值,使得左边部分的元素值都小于target
,右边部分的元素值都大于target
。递归的过程中,我们只需要处理包含前k个小元素的部分,当我们处理到的元素下标是第k个元素时,划分结束,原数组的前k个元素就是整个数组中的前k个小元素。
时间复杂度:$O(n)$ 空间复杂度:$O(\log{}n)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public int [] getLeastNumbers(int [] arr, int k) { process(arr, 0 , arr.length - 1 , k); return Arrays.copyOfRange(arr, 0 , k); } public void process (int [] arr, int l, int r, int k) { if (k == 0 ) return ; int i = l - 1 , j = r + 1 , target = arr[(l + r) >> 1 ]; while (i < j) { do i++; while (arr[i] < target); do j--; while (arr[j] > target); if (i < j) swap(arr, i, j); } if (j + 1 == k) { return ; } else if (j + 1 > k) { process(arr, l, j, k); } else { process(arr, j + 1 , r, k); } } public void swap (int [] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户 内存消耗:39.7 MB, 在所有 Java 提交中击败了74.27%的用户
-------------本文结束 感谢您的阅读-------------
文章对您有帮助,可以打赏一杯咖啡,鼓励我继续创作!