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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時(shí)間:2023/12/4 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构与算法--最小的k个数 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最小的k個(gè)數(shù)

  • 題目:輸入n個(gè)整數(shù),找出其中最小的k個(gè)數(shù),例如輸入4,5,6,7,8,9這六個(gè)數(shù)字,則最小的4個(gè)是4,5,6,7
方案一
  • 還是最直觀的方法,先排序,最快的是快排O(nlog2n),然后遍歷前面k個(gè)數(shù)組,得到我們需要的答案,這個(gè)最簡(jiǎn)單方案應(yīng)該有更優(yōu)實(shí)現(xiàn)
方案二
  • 題意,我們需要找出最小的k個(gè)數(shù)字,還是從快排的思路收到啟發(fā)
  • 我們同樣基于快速排序,但是只找出第k個(gè)大的數(shù)字
  • 因?yàn)榭炫胚^(guò)程中會(huì)將比基準(zhǔn)值小的放到 之前,比基準(zhǔn)值大的放到后面,因此只需要找到第k個(gè)大的數(shù)字,在之前的數(shù)就是我們需要的數(shù)
  • 基于如上分析有如下代碼:
/*** 找出數(shù)組中最小的K個(gè)數(shù)** @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個(gè)大的數(shù),將小的放k前面* 將大的放k后,得到數(shù)組中最小的k個(gè)數(shù)就是下標(biāo)是0~k的所有數(shù)*/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;} }
  • 基于快排的方案是有限制的,因?yàn)槲覀冃枰薷妮斎氲臄?shù)組,最后的順序是變化的,如果要求不能修改輸入的參數(shù),我們是否有其他方案。
方案三
  • 既然不能修改原值,那么我們復(fù)制一個(gè)我們需要的值,還是空間換時(shí)間的做法
  • 我們建一個(gè)原數(shù)組大小的容器用來(lái)存儲(chǔ),接著在容器中找出最小的k個(gè)數(shù)
  • 本次我們需要的存儲(chǔ)的特點(diǎn)是能快速的找到最小值,這樣重復(fù)查找k次最小值,就能得到結(jié)果
  • 如果我們用二叉查找樹(shù)來(lái)實(shí)現(xiàn)這個(gè)容器,那么我們每次查詢的時(shí)間復(fù)雜度是O(logn),也就是層高度,那么k次查詢就是O(klogn)
  • 但是還有其他變種的二叉查找樹(shù)二叉堆中對(duì)小堆,之前文章:數(shù)據(jù)結(jié)構(gòu)與算法–二叉堆(最大堆,最小堆)實(shí)現(xiàn)及原理對(duì)最大堆,最小堆的實(shí)現(xiàn)有詳細(xì)的解釋
  • 最小堆的特點(diǎn)在于能在O(1)時(shí)間內(nèi)找到最小值,就是二叉堆的根節(jié)點(diǎn)
  • 并且二叉堆的結(jié)構(gòu)特性就在于能夠快速的查詢,我們將所有數(shù)據(jù)構(gòu)造成一個(gè)最小堆,然后經(jīng)k次O(1)的操作,就能得到結(jié)果
  • 經(jīng)如上分析有如下代碼:
/*** 找出數(shù)組中最小的K個(gè)數(shù)** @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]+",");}}/*** 利用二叉堆,最小堆的結(jié)構(gòu)特性,構(gòu)建最小堆后,每次去跟節(jié)點(diǎn)都是最小的節(jié)點(diǎn)* 循環(huán)取k個(gè)最小堆中根元素,得到我們的結(jié)果* */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;} }

方案四

  • 如上最小堆的實(shí)現(xiàn)中雖然找最小值都是O(1),但是在構(gòu)造最小堆的過(guò)程中我們需要O(logn)的時(shí)間復(fù)雜度,如果題目要是海量數(shù)據(jù),其實(shí)我們也可以用最大堆
  • 我們可以用k個(gè)元素的最大堆,當(dāng)堆滿后,每次讀入原數(shù)組中一個(gè)數(shù)據(jù),與最大數(shù)據(jù)比較(O(1)時(shí)間)
  • 如果比最大數(shù)據(jù)要小,我們刪除最大數(shù)據(jù),插入當(dāng)前值,直到整個(gè)數(shù)組遍歷完
  • 此時(shí)得到的最大堆中k個(gè)數(shù)據(jù)就是我們需要的數(shù)據(jù)
  • 這種方案可以用來(lái)處理海量數(shù)據(jù)時(shí)候內(nèi)存占用過(guò)多的問(wèn)題。
  • 海量數(shù)據(jù)情況下,空間復(fù)雜度O(k)的實(shí)現(xiàn)方式如下:
/*** 找出數(shù)組中最小的K個(gè)數(shù)** @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+",");}}/*** 利用二叉堆,最大堆,處理海量數(shù)據(jù)情況下獲取前k個(gè)最小的數(shù)據(jù)* */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;} }
解法對(duì)比
  • 第一種方案直接排序遍歷平均時(shí)間復(fù)雜度是O(nlog2n),比第二種思路上更容易理解,但是同時(shí)也有明顯的限制會(huì)修改入?yún)?shù)組
  • 第二種解法,也是基于快排思路,但是可以在中間退出,因此時(shí)間復(fù)雜度小于O(nlog2n),同樣也會(huì)修改入?yún)?shù)組
  • 第三種方法,最小堆的方式,先構(gòu)建最小堆,在讀取,這種有兩個(gè)明顯優(yōu)點(diǎn),一個(gè)是沒(méi)有修改輸入的數(shù)據(jù),因?yàn)槲覀冎皇亲x取入?yún)?shù)組中的數(shù)字,所有寫操作都是在最小堆中完成,二是解法簡(jiǎn)單,缺點(diǎn)也明顯,時(shí)間復(fù)雜度更大,構(gòu)建時(shí)候需要insert,n次,每次insert的平均時(shí)間復(fù)雜度是O(logn),因此是O(nlogn)
  • 第四種算法適合海量數(shù)據(jù)的輸入,如果題目要求的是海量數(shù)數(shù)據(jù)中找k個(gè)數(shù),內(nèi)存的大小限制,不可能全讀取如內(nèi)存,這時(shí)候,我們只一次讀取一個(gè)數(shù)據(jù)進(jìn)內(nèi)存,只要求內(nèi)存容納的下最大堆中的k個(gè)數(shù)據(jù)即可,能有效解決n很大,k很小的情況,時(shí)間復(fù)雜度也是O(nlogk)

上一篇:數(shù)據(jù)結(jié)構(gòu)與算法–兩個(gè)鏈表中第一個(gè)公共節(jié)點(diǎn)
下一篇:數(shù)據(jù)結(jié)構(gòu)與算法–數(shù)字在排序數(shù)組中出現(xiàn)次數(shù)

總結(jié)

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

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