日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[剑指offer][JAVA][面试第40题][最小的k个数][快选][堆][BST]

發(fā)布時間:2023/12/10 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [剑指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)
class Solution {public int[] getLeastNumbers(int[] arr, int k) {Arrays.sort(arr);int[] a = new int[k] ;/*for(int j = 0; j < k ; j++){a[j] = arr[j];}*/System.arraycopy(arr, 0, a, 0, k);return a;//return Arrays.copyOfRange(arr, 0, k);} }
2. 堆

使用堆數(shù)據(jù)結(jié)構(gòu)來輔助得到最小的 k 個數(shù)。堆的性質(zhì)是每次可以找出最大或最小的元素。我們可以使用一個大小為 k 的最大堆(大頂堆),將數(shù)組中的元素依次入堆,當堆的大小超過 k 時,便將多出的元素從堆頂彈

時間復雜度:O(Nlogk) 空間復雜度:O(k)
使用了一個大小為 k 的堆

public int[] getLeastNumbers(int[] arr, int k) {if (k == 0) {return new int[0];}// 使用一個最大堆(大頂堆)// Java 的 PriorityQueue 默認是小頂堆,添加 comparator 參數(shù)使其變成最大堆Queue<Integer> heap = new PriorityQueue<>(k, (i1, i2) -> Integer.compare(i2, i1));for (int e : arr) {// 當前數(shù)字小于堆頂元素才會入堆if (heap.isEmpty() || heap.size() < k || e < heap.peek()) {heap.offer(e);}if (heap.size() > k) {heap.poll(); // 刪除堆頂最大元素}}// 將堆中的元素存入數(shù)組int[] res = new int[heap.size()];int j = 0;for (int e : heap) {res[j++] = e;}return res; }作者:nettee 鏈接: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-/
3. 快排變形
  • “查找第 k 大的元素”是一類算法問題,稱為選擇問題。
  • 找第 k 大的數(shù),或者找前 k 大的數(shù),有一個經(jīng)典的 quick select(快速選擇)算法。
  • 這個名字和 quick sort(快速排序)很像,算法的思想也和快速排序類似,都是分治法的思想


時間復雜度:期望O(N) 最壞O(N^2) 空間復雜度:O(1)

public int[] getLeastNumbers(int[] arr, int k) {if (k == 0) {return new int[0];} else if (arr.length <= k) {return arr;}// 原地不斷劃分數(shù)組partitionArray(arr, 0, arr.length - 1, k);// 數(shù)組的前 k 個數(shù)此時就是最小的 k 個數(shù),將其存入結(jié)果int[] res = new int[k];for (int i = 0; i < k; i++) {res[i] = arr[i];}return res; }void partitionArray(int[] arr, int lo, int hi, int k) {// 做一次 partition 操作int m = partition(arr, lo, hi);// 此時數(shù)組前 m 個數(shù),就是最小的 m 個數(shù)if (k == m) {// 正好找到最小的 k(m) 個數(shù)return;} else if (k < m) {// 最小的 k 個數(shù)一定在前 m 個數(shù)中,遞歸劃分partitionArray(arr, lo, m-1, k);} else {// 在右側(cè)數(shù)組中尋找最小的 k-m 個數(shù)partitionArray(arr, m+1, hi, k);} }// partition 函數(shù)和快速排序中相同,具體可參考快速排序相關的資料 // 代碼參考 Sedgewick 的《算法4》 int partition(int[] a, int lo, int hi) {int i = lo;int j = hi + 1;int v = a[lo];while (true) { while (a[++i] < v) {if (i == hi) {break;}}while (a[--j] > v) {if (j == lo) {break;}}if (i >= j) {break;}swap(a, i, j);}swap(a, lo, j);// a[lo .. j-1] <= a[j] <= a[j+1 .. hi]return j; }void swap(int[] a, int i, int j) {int temp = a[i];a[i] = a[j];a[j] = temp; }作者:nettee 鏈接: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-/
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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。