[剑指offer][JAVA][面试第40题][最小的k个数][快选][堆][BST]
生活随笔
收集整理的這篇文章主要介紹了
[剑指offer][JAVA][面试第40题][最小的k个数][快选][堆][BST]
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【問題描述】面試第40題 最小的k個數
輸入整數數組 arr ,找出其中最小的 k 個數。例如,輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是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
- 需要先把該數組排序(從小到大)。
- 截取前k個數返回需要的數組。
時間復雜度:O(N^2) 空間復雜度:O(N)
2. 堆
使用堆數據結構來輔助得到最小的 k 個數。堆的性質是每次可以找出最大或最小的元素。我們可以使用一個大小為 k 的最大堆(大頂堆),將數組中的元素依次入堆,當堆的大小超過 k 時,便將多出的元素從堆頂彈
時間復雜度:O(Nlogk) 空間復雜度:O(k)
使用了一個大小為 k 的堆
3. 快排變形
- “查找第 k 大的元素”是一類算法問題,稱為選擇問題。
- 找第 k 大的數,或者找前 k 大的數,有一個經典的 quick select(快速選擇)算法。
- 這個名字和 quick sort(快速排序)很像,算法的思想也和快速排序類似,都是分治法的思想
時間復雜度:期望O(N) 最壞O(N^2) 空間復雜度:O(1)
4. 計數排序
時間復雜度:O(N) 空間復雜度:O(N)
class Solution {public int[] getLeastNumbers(int[] arr, int k) {if (k == 0 || arr.length == 0) {return new int[0];}// 統計每個數字出現的次數int[] counter = new int[10001];for (int num: arr) {counter[num]++;}// 根據counter數組從頭找出k個數作為返回結果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是數字, value是該數字的個數。// cnt表示當前map總共存了多少個數字。TreeMap<Integer, Integer> map = new TreeMap<>();int cnt = 0;for (int num: arr) {// 1. 遍歷數組,若當前map中的數字個數小于k,則map中當前數字對應個數+1if (cnt < k) {map.put(num, map.getOrDefault(num, 0) + 1);cnt++;continue;} // 2. 否則,取出map中最大的Key(即最大的數字), 判斷當前數字與map中最大數字的大小關系:// 若當前數字比map中最大的數字還大,就直接忽略;// 若當前數字比map中最大的數字小,則將當前數字加入map中,并將map中的最大數字的個數-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)
【總結】
1.堆/快速選擇比較
看起來分治法的快速選擇算法的時間、空間復雜度都優于使用堆的方法,但是要注意到快速選擇算法的幾點局限性:
- 算法需要修改原數組,如果原數組不能修改的話,還需要拷貝一份數組,空間復雜度就上去了。
- 算法需要保存所有的數據。如果把數據看成輸入流的話,使用堆的方法是來一個處理一個,不需要保存數據,只需要保存 k 個元素的最大堆。而快速選擇的方法需要先保存下來所有的數據,再運行算法。當數據量非常大的時候,甚至內存都放不下的時候,就麻煩了。所以當數據量大的時候還是用基于堆的方法比較好
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/
總結
以上是生活随笔為你收集整理的[剑指offer][JAVA][面试第40题][最小的k个数][快选][堆][BST]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在Debian上安装配置ownClo
- 下一篇: 软件测试:Lab 2 Selenium