[剑指offer][JAVA][面试第40题][最小的k个数][快选][堆][BST]
生活随笔
收集整理的這篇文章主要介紹了
[剑指offer][JAVA][面试第40题][最小的k个数][快选][堆][BST]
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
【問題描述】面試第40題 最小的k個數(shù)
輸入整數(shù)數(shù)組 arr ,找出其中最小的 k 個數(shù)。例如,輸入4、5、1、6、2、7、3、8這8個數(shù)字,則最小的4個數(shù)字是1、2、3、4。 示例 : 輸入:arr = [3,2,1], k = 2 輸出:[1,2] 或者 [2,1] 0 <= k <= arr.length <= 10000 0 <= arr[i] <= 10000【解答思路】
1. Arrays.sort
- 需要先把該數(shù)組排序(從小到大)。
- 截取前k個數(shù)返回需要的數(shù)組。
時間復雜度:O(N^2) 空間復雜度:O(N)
2. 堆
使用堆數(shù)據(jù)結(jié)構(gòu)來輔助得到最小的 k 個數(shù)。堆的性質(zhì)是每次可以找出最大或最小的元素。我們可以使用一個大小為 k 的最大堆(大頂堆),將數(shù)組中的元素依次入堆,當堆的大小超過 k 時,便將多出的元素從堆頂彈
時間復雜度:O(Nlogk) 空間復雜度:O(k)
使用了一個大小為 k 的堆
3. 快排變形
- “查找第 k 大的元素”是一類算法問題,稱為選擇問題。
- 找第 k 大的數(shù),或者找前 k 大的數(shù),有一個經(jīng)典的 quick select(快速選擇)算法。
- 這個名字和 quick sort(快速排序)很像,算法的思想也和快速排序類似,都是分治法的思想
時間復雜度:期望O(N) 最壞O(N^2) 空間復雜度:O(1)
4. 計數(shù)排序
時間復雜度:O(N) 空間復雜度:O(N)
class Solution {public int[] getLeastNumbers(int[] arr, int k) {if (k == 0 || arr.length == 0) {return new int[0];}// 統(tǒng)計每個數(shù)字出現(xiàn)的次數(shù)int[] counter = new int[10001];for (int num: arr) {counter[num]++;}// 根據(jù)counter數(shù)組從頭找出k個數(shù)作為返回結(jié)果int[] res = new int[k];int idx = 0;for (int num = 0; num < counter.length; num++) {while (counter[num]-- > 0 && idx < k) {res[idx++] = num;}if (idx == k) {break;}}return res;} }作者:sweetiee 鏈接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/3chong-jie-fa-miao-sha-topkkuai-pai-dui-er-cha-sou/5. 二叉搜索樹BST(前K大有序)
class Solution {public int[] getLeastNumbers(int[] arr, int k) {if (k == 0 || arr.length == 0) {return new int[0];}// TreeMap的key是數(shù)字, value是該數(shù)字的個數(shù)。// cnt表示當前map總共存了多少個數(shù)字。TreeMap<Integer, Integer> map = new TreeMap<>();int cnt = 0;for (int num: arr) {// 1. 遍歷數(shù)組,若當前map中的數(shù)字個數(shù)小于k,則map中當前數(shù)字對應個數(shù)+1if (cnt < k) {map.put(num, map.getOrDefault(num, 0) + 1);cnt++;continue;} // 2. 否則,取出map中最大的Key(即最大的數(shù)字), 判斷當前數(shù)字與map中最大數(shù)字的大小關系:// 若當前數(shù)字比map中最大的數(shù)字還大,就直接忽略;// 若當前數(shù)字比map中最大的數(shù)字小,則將當前數(shù)字加入map中,并將map中的最大數(shù)字的個數(shù)-1。Map.Entry<Integer, Integer> entry = map.lastEntry();if (entry.getKey() > num) {map.put(num, map.getOrDefault(num, 0) + 1);if (entry.getValue() == 1) {map.pollLastEntry();} else {map.put(entry.getKey(), entry.getValue() - 1);}}}// 最后返回map中的元素int[] res = new int[k];int idx = 0;for (Map.Entry<Integer, Integer> entry: map.entrySet()) {int freq = entry.getValue();while (freq-- > 0) {res[idx++] = entry.getKey();}}return res;} }作者:sweetiee 鏈接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/3chong-jie-fa-miao-sha-topkkuai-pai-dui-er-cha-sou/時間復雜度:O(NlogN) 空間復雜度:O(N)
【總結(jié)】
1.堆/快速選擇比較
看起來分治法的快速選擇算法的時間、空間復雜度都優(yōu)于使用堆的方法,但是要注意到快速選擇算法的幾點局限性:
- 算法需要修改原數(shù)組,如果原數(shù)組不能修改的話,還需要拷貝一份數(shù)組,空間復雜度就上去了。
- 算法需要保存所有的數(shù)據(jù)。如果把數(shù)據(jù)看成輸入流的話,使用堆的方法是來一個處理一個,不需要保存數(shù)據(jù),只需要保存 k 個元素的最大堆。而快速選擇的方法需要先保存下來所有的數(shù)據(jù),再運行算法。當數(shù)據(jù)量非常大的時候,甚至內(nèi)存都放不下的時候,就麻煩了。所以當數(shù)據(jù)量大的時候還是用基于堆的方法比較好
2. 一題多解 按照自己的掌握情況選擇 熟悉or了解
參考鏈接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/tu-jie-top-k-wen-ti-de-liang-chong-jie-fa-you-lie-/
參考鏈接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/3chong-jie-fa-miao-sha-topkkuai-pai-dui-er-cha-sou/
總結(jié)
以上是生活随笔為你收集整理的[剑指offer][JAVA][面试第40题][最小的k个数][快选][堆][BST]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在Debian上安装配置ownClo
- 下一篇: 软件测试:Lab 2 Selenium