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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

数据结构与算法--最小的k个数

發布時間:2023/12/4 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构与算法--最小的k个数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最小的k個數

  • 題目:輸入n個整數,找出其中最小的k個數,例如輸入4,5,6,7,8,9這六個數字,則最小的4個是4,5,6,7
方案一
  • 還是最直觀的方法,先排序,最快的是快排O(nlog2n),然后遍歷前面k個數組,得到我們需要的答案,這個最簡單方案應該有更優實現
方案二
  • 題意,我們需要找出最小的k個數字,還是從快排的思路收到啟發
  • 我們同樣基于快速排序,但是只找出第k個大的數字
  • 因為快排過程中會將比基準值小的放到 之前,比基準值大的放到后面,因此只需要找到第k個大的數字,在之前的數就是我們需要的數
  • 基于如上分析有如下代碼:
/*** 找出數組中最小的K個數** @author liaojiamin* @Date:Created in 10:18 2021/6/16*/ public class GetLeastNumbers {public static void main(String[] args) {Integer[] arrayData = new Integer[20];Random random = new Random();for (int i = 0; i < 20; i++) {arrayData[i] = random.nextInt(50);System.out.print(arrayData[i]+",");}System.out.println();Integer[] newArray = getLeastNumbers(arrayData, 10);for (Integer integer : newArray) {System.out.print(integer+",");}}/*** 按快速排序思路,找到第k個大的數,將小的放k前面* 將大的放k后,得到數組中最小的k個數就是下標是0~k的所有數*/public static Integer[] getLeastNumbers(Integer[] array, Integer key) {if (array == null || array.length <= 0 || array.length < key) {return new Integer[]{};}if (array.length == key) {return array;}return quickSort(array, 0, array.length-1, key);}public static Integer[] quickSort(Integer[] array, Integer left, Integer right, Integer key) {if (left < right) {Integer middle = quickSortSwap(array, left, right);if (middle == key) {return Arrays.copyOfRange(array, 0, key);}quickSort(array, left, middle - 1, key);quickSort(array, middle + 1, right, key);}return Arrays.copyOfRange(array, 0, key);}public static Integer quickSortSwap(Integer[] array, Integer left, Integer right) {if (left < right) {Integer position = array[left];while (left < right) {while (left < right && array[right] > position) {right--;}if (left < right) {array[left] = array[right];left++;}while (left < right && array[left] < position) {left++;}if(left < right){array[right] = array[left];right --;}}array[left] = position;}return left;} }
  • 基于快排的方案是有限制的,因為我們需要修改輸入的數組,最后的順序是變化的,如果要求不能修改輸入的參數,我們是否有其他方案。
方案三
  • 既然不能修改原值,那么我們復制一個我們需要的值,還是空間換時間的做法
  • 我們建一個原數組大小的容器用來存儲,接著在容器中找出最小的k個數
  • 本次我們需要的存儲的特點是能快速的找到最小值,這樣重復查找k次最小值,就能得到結果
  • 如果我們用二叉查找樹來實現這個容器,那么我們每次查詢的時間復雜度是O(logn),也就是層高度,那么k次查詢就是O(klogn)
  • 但是還有其他變種的二叉查找樹二叉堆中對小堆,之前文章:數據結構與算法–二叉堆(最大堆,最小堆)實現及原理對最大堆,最小堆的實現有詳細的解釋
  • 最小堆的特點在于能在O(1)時間內找到最小值,就是二叉堆的根節點
  • 并且二叉堆的結構特性就在于能夠快速的查詢,我們將所有數據構造成一個最小堆,然后經k次O(1)的操作,就能得到結果
  • 經如上分析有如下代碼:
/*** 找出數組中最小的K個數** @author liaojiamin* @Date:Created in 10:18 2021/6/16*/ public class GetLeastNumbers {public static void main(String[] args) {Integer[] arrayData = new Integer[20];Random random = new Random();for (int i = 0; i < 20; i++) {arrayData[i] = random.nextInt(50);System.out.print(arrayData[i]+",");}System.out.println();Integer[] heapArray = getLeastNumbersByBinaryHeapMax(arrayData, 10);for (int i = 0; i < heapArray.length; i++) {System.out.print(heapArray[i]+",");}}/*** 利用二叉堆,最小堆的結構特性,構建最小堆后,每次去跟節點都是最小的節點* 循環取k個最小堆中根元素,得到我們的結果* */public static Integer[] getLeastNumbersByBinaryHeapMax(Integer[] array, Integer key){if (array == null || array.length <= 0 || array.length < key) {return new Integer[]{};}if (array.length == key) {return array;}Integer size = (array.length + 2 )*11/10;BinaryHeap binaryHeap = new BinaryHeap(size);for (int i = 0; i < array.length; i++) {binaryHeap.insert(new AnyType(array[i]));}Integer[] result = new Integer[key];for (Integer i = 0; i < key; i++) {result[i] = Integer.valueOf(binaryHeap.deleteMin().getElement().toString());}return result;} }

方案四

  • 如上最小堆的實現中雖然找最小值都是O(1),但是在構造最小堆的過程中我們需要O(logn)的時間復雜度,如果題目要是海量數據,其實我們也可以用最大堆
  • 我們可以用k個元素的最大堆,當堆滿后,每次讀入原數組中一個數據,與最大數據比較(O(1)時間)
  • 如果比最大數據要小,我們刪除最大數據,插入當前值,直到整個數組遍歷完
  • 此時得到的最大堆中k個數據就是我們需要的數據
  • 這種方案可以用來處理海量數據時候內存占用過多的問題。
  • 海量數據情況下,空間復雜度O(k)的實現方式如下:
/*** 找出數組中最小的K個數** @author liaojiamin* @Date:Created in 10:18 2021/6/16*/ public class GetLeastNumbers {public static void main(String[] args) {Integer[] arrayData = new Integer[20];Random random = new Random();for (int i = 0; i < 20; i++) {arrayData[i] = random.nextInt(50);System.out.print(arrayData[i]+",");}System.out.println();Integer[] maxArray = getLeastNumberByBinaryHeapMax(arrayData, 10);for (Integer integer : maxArray) {System.out.print(integer+",");}}/*** 利用二叉堆,最大堆,處理海量數據情況下獲取前k個最小的數據* */public static Integer[] getLeastNumberByBinaryHeapMax(Integer[] array, Integer key){if (array == null || array.length <= 0 || array.length < key) {return new Integer[]{};}if (array.length == key) {return array;}Integer size = (array.length+2)*11/10;BinaryHeapMax binaryHeapMax = new BinaryHeapMax(size);for (int i = 0; i < array.length; i++) {AnyType anyType = new AnyType(array[i]);if(binaryHeapMax.heapSize() >= key){Integer heapMax = Integer.valueOf(binaryHeapMax.findMax().getElement().toString());if(array[i] < heapMax){binaryHeapMax.deleteMax();binaryHeapMax.insert(anyType);}}else {binaryHeapMax.insert(anyType);}}AnyType[] anyTypes = binaryHeapMax.getAppHeapData();Integer[] result = new Integer[key];for (int i = 0; i < anyTypes.length; i++) {result[i] = Integer.valueOf(anyTypes[i].getElement().toString());}return result;} }
解法對比
  • 第一種方案直接排序遍歷平均時間復雜度是O(nlog2n),比第二種思路上更容易理解,但是同時也有明顯的限制會修改入參數組
  • 第二種解法,也是基于快排思路,但是可以在中間退出,因此時間復雜度小于O(nlog2n),同樣也會修改入參數組
  • 第三種方法,最小堆的方式,先構建最小堆,在讀取,這種有兩個明顯優點,一個是沒有修改輸入的數據,因為我們只是讀取入參數組中的數字,所有寫操作都是在最小堆中完成,二是解法簡單,缺點也明顯,時間復雜度更大,構建時候需要insert,n次,每次insert的平均時間復雜度是O(logn),因此是O(nlogn)
  • 第四種算法適合海量數據的輸入,如果題目要求的是海量數數據中找k個數,內存的大小限制,不可能全讀取如內存,這時候,我們只一次讀取一個數據進內存,只要求內存容納的下最大堆中的k個數據即可,能有效解決n很大,k很小的情況,時間復雜度也是O(nlogk)

上一篇:數據結構與算法–兩個鏈表中第一個公共節點
下一篇:數據結構與算法–數字在排序數組中出現次數

總結

以上是生活随笔為你收集整理的数据结构与算法--最小的k个数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。