LeetCode題解:劍指 Offer 40. 最小的k個數,二叉堆,JavaScript,詳細註釋
原題連結:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/
解題思路:
- 該題可使用堆解決,利用了堆能夠快速插入和取出元素,並始終能夠按要求排序的特點。
- 使用JavaScript實現一個二叉堆,並將陣列元素依次存入堆中,之後再依次取出k個元素即可。
/**
* @param {number[]} arr
* @param {number} k
* @return {number[]}
*/
var getLeastNumbers = function(arr, k) {
let result = []; // 儲存結果
let heap = new BinaryHeap((a, b) => a - b); // 建立一個堆,元素由小到大排序
// 將陣列元素都插入堆
for (let i = 0; i < arr.length; i++) {
heap.insert(arr[i]);
}
// 從堆中按順序取出k個元素
for (let j = 0; j < k; j++) {
result.push(heap.deleteHead());
}
return result;
};
class BinaryHeap {
constructor(compare) {
this.data = []; // 使用陣列儲存堆
this.compare = compare; // 堆元素的排序函式
}
// 向堆插入元素
insert(value) {
this.insertAt(this.data.length, value);
}
// 將元素插入到index位置
insertAt(index, value) {
// 先將元素插入到指定的位置
this.data[index] = value;
let fatherIndex = index;
// 對比當前節點與其父節點,如果當前節點更小就交換它們
// Math.floor((index - 1) / 2)是父節點在陣列中的索引
while (
index > 0 &&
// 使用傳入的對比函式比較大小
this.compare(
value,
this.data[(fatherIndex = Math.floor((index - 1) / 2))]
) < 0
) {
// 將父節點移動到當前位置
this.data[index] = this.data[fatherIndex];
// 將插入的值移動到父節點位置
this.data[fatherIndex] = value;
// 更新索引為父節點索引,繼續下一次迴圈
index = fatherIndex;
}
}
// 刪除最大節點
deleteHead() {
return this.delete(0);
}
// 將指定位置的元素刪除
delete(index) {
// 如果堆為空,則不進行刪除操作
if (this.data.length === 0) {
return;
}
let value = this.data[index]; // 將要刪除的元素快取
let parent = index; // 以當前元素為起始,向下整理堆
// 不斷向子節點整理堆,每次迴圈將子節點中經過compare方法對比後較大者與父節點調換
while (parent < this.data.length) {
let left = parent * 2 + 1; // 左子節點索引
let right = parent * 2 + 2; // 右子節點索引
// 沒有左子節點,表示當前節點已經是最後一個節點
if (left >= this.data.length) {
break;
}
// 沒有右子節點,則直接將左子節點提前到父節點即可
// 該左子節點即為最後一個節點
if (right >= this.data.length) {
this.data[parent] = this.data[left];
parent = left;
break;
}
// 使用compare方法比較左右子節點的大小,更大的補到父節點
if (this.compare(this.data[left], this.data[right]) < 0) {
// 由於被刪除的節點已儲存,此處只需要將子節點複製到當前父節點即可
this.data[parent] = this.data[left];
// 完成移動後將父節點指標移動到子節點,供下一次整理使用
parent = left;
} else {
this.data[parent] = this.data[right];
parent = right;
}
}
// 檢視最後的空位是不是最後的葉子節點
if (parent < this.data.length - 1) {
// 如果還未整理到葉子節點,則繼續向下整理
this.insertAt(parent, this.data.pop());
} else {
// 當完成整理時,最後一個節點即為多於元素,直接彈出陣列即可
this.data.pop();
}
// 返回被刪除的元素
return value;
}
}
相關文章
- Leetcode 劍指 Offer 40. 最小的k個數LeetCode
- LeetCode題解:264. 醜數 II,二叉堆,JavaScript,詳細註釋LeetCodeJavaScript
- 【劍指offer】把陣列排成最小的數陣列
- 劍指offer:旋轉陣列的最小數字陣列
- 劍指offer 旋轉陣列的最小數字陣列
- 《劍指offer》JAVA題解,LeetCode評測JavaLeetCode
- 劍指Offer-把陣列中的數排成一個最小的數陣列
- 劍指Offer題解合集
- 劍指Offer-34-把陣列排成最小的數陣列
- 劍指offer——把陣列排成最小的數C++陣列C++
- 劍指offer-轉陣列的最小數字-php陣列PHP
- LeetCode|劍指 Offer 49.醜數LeetCode
- 【劍指offer】7.旋轉陣列的最小數字陣列
- 劍指 Offer 11. 旋轉陣列的最小數字陣列
- 【劍指 Offer】11. 旋轉陣列的最小數字陣列
- 劍指offer面試題15 連結串列中倒數第K個結點面試題
- 劍指offer——重建二叉樹二叉樹
- 【劍指offer】二叉樹深度二叉樹
- Leetcode劍指offer(八)LeetCode
- 劍指offer-JavaScript版JavaScript
- 力扣 - 劍指 Offer 45. 把陣列排成最小的數力扣陣列
- 【leetcode】劍指 Offer 16. 數值的整數次方LeetCode
- LeetCode-劍指Offer刷題記錄LeetCode
- 劍指offer(四)重建二叉樹二叉樹
- 每日一題 - 劍指 Offer 54. 二叉搜尋樹的第k大節點每日一題
- 劍指offer面試題11 數值的整數次方面試題
- 【劍指offer】旋轉陣列的最小值陣列
- 《劍指offer》:[58]二叉樹的下一個結點二叉樹
- 劍指Offer-40-二叉樹的深度二叉樹
- 劍指offer——二叉樹的映象C++二叉樹C++
- 【劍指offer】27. 二叉樹的映象二叉樹
- 劍指offer——二叉樹的深度C++二叉樹C++
- 《劍指offer》:[59]對稱的二叉樹二叉樹
- 《劍指offer》:[39]求解二叉樹的深度二叉樹
- 劍指 Offer 07. 重建二叉樹二叉樹
- 【劍指offer】判斷二叉樹平衡二叉樹
- 【LeetCode刷題(簡單程度)】劍指 Offer 57. 和為s的兩個數字LeetCode
- 劍指Offer 表示數值的字串字串