劍指 Offer 40 最小的k個數

2021-10-10 20:48:14 字數 3307 閱讀 3005

輸入整數陣列 arr ,找出其中最小的 k 個數。例如,輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1、2、3、4。

示例 1:

輸入:arr = [3,2,1], k = 2

輸出:[1,2] 或者 [2,1]

示例 2:

輸入:arr = [0,1,2,1], k = 1

輸出:[0]

限制:0 <= k <= arr.length <= 10000

0 <= arr[i] <= 10000

方法一:排序

var

getleastnumbers

=function

(arr, k)

;

改變原陣列,使用高階排序(**用的是快排)

複雜度分析

時間複雜度:o(nlogn),其中 n是陣列 arr 的長度。演算法的時間複雜度即排序的時間複雜度。

空間複雜度:o(logn),排序所需額外的空間複雜度為o(logn)。

方法二:快排思想partition方法

我們可以借鑑快速排序的思想。我們知道快排的劃分函式每次執行完後都能將陣列分成兩個部分,小於等於分界值index 的元素的都會被放到陣列的左邊,大於的都會被放到陣列的右邊,然後返回分界值的下標。與快速排序不同的是,快速排序會根據分界值的下標遞迴處理劃分的兩側,而這裡我們只處理劃分的一邊。(二分)index為k,比k小的放前面,比k大的放後面,輸出前k個數。

回顧快速排序中的 partition 操作,可以將元素arr[0]放入排序後的正確位置,並且返回這個位置index。利用 partition 的特點,演算法流程如下:

如果index = k-1,(下標)說明第 k 個元素已經放入正確位置,返回前 k 個元素

如果k-1 < index,第 k 個元素在[left, index - 1]之間,縮小查詢範圍,繼續查詢

如果index < k-1,第 k 個元素在[index + 1, right] 之間,縮小查詢範圍,繼續查詢

/**

* @param arr

* @param k

* @return

*/var

getleastnumbers

=function

(arr, k)

else

if(index > k-1)

}return arr.

slice(0

, k);}

;function

partition

(arr, start, end)

[arr[left]

, arr[right]]=

[arr[right]

, arr[left]];

++left;

--right;

}[arr[right]

, arr[start]]=

[arr[start]

, arr[right]];

return right;

}

var

getleastnumbers

=function

(arr, k)

const

qucikselect

=(nums, start, end)

=>

const pivot = nums[start]

;let i = start, j = end;

while

(i < j)

if(i < j)

// 找出左邊第乙個大於參照數的下標 i ,並記錄

while

(i < j && nums[i]

< pivot)

if(i < j)

} nums[i]

= pivot;

if(i === k -1)

else

if(i < k -1)

else

}qucikselect

(arr,

0, len -1)

;return arr.

slice(0

, k);}

;

/**

* @param arr

* @param k

* @return

*/var

getleastnumbers

=function

(arr, k)

else

if(index > k-1)

}return arr.

slice(0

,k);};

function

partition

(arr,l,r)

return r;

}

改變原陣列

複雜度分析

方法三:最大堆

堆是一種非常常用的資料結構。最大堆的性質是:節點值大於子節點的值,堆頂元素是最大元素。利用這個性質,整體的演算法流程如下:

/**

* @param arr

* @param k

* @return

*/var

getleastnumbers

=function

(arr, k)

}return heap;};

function

buildheap

(arr,i)

}function

maxheap

(arr,i)

else largest = i;

//否則為根

if(right < arr.length && arr[right]

> arr[largest])if

(largest !== i)

}

利用堆求 top k 問題的優勢

這種求 top k 問題是可以使用排序來處理,但當我們需要在乙個動態陣列中求 top k 元素怎麼辦?

動態陣列可能會插入或刪除元素,難道我們每次求 top k 問題的時候都需要對陣列進行重新排序嗎?那每次的時間複雜度都為 o(nlogn)

這裡就可以使用堆,我們可以維護乙個 k 大小的小頂堆,當有資料被新增到陣列中時,就將它與堆頂元素比較,如果比堆頂元素大,則將這個元素替換掉堆頂元素,然後再堆化成乙個小頂堆;如果比堆頂元素小,則不做處理。這樣,每次求 top k 問題的時間複雜度僅為 o(logk)

複雜度分析

劍指offer40 最小的k個數

輸入n個整數,找出其中最小的k個數。注意 資料保證k一定小於等於輸入陣列的長度 輸出陣列內元素請按從小到大順序排序 樣例 輸入 1,2,3,4,5,6,7,8 k 4 輸出 1,2,3,4 思路1 用大頂堆儲存k個數,然後不斷的遍歷陣列,若是陣列中的數小於堆頂元素,則替換。實踐複雜度為o nlogk...

劍指offer40 最小的 K 個數

題目描述 輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,思路 方法一 維護乙個大小為k的大頂堆,複雜度 o nlogk o k 特別適合處理海量資料 public class solution priorityqueuemax...

劍指offer40 最小的k個數

問題描述 輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,方法1 o nlogn def getleastnumbers input,k input.sort return input 4 a sorted input inpu...