輸入整數陣列 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...