1. 程式人生 > 其它 >LeetCode題解:劍指 Offer 40. 最小的k個數,二叉堆,JavaScript,詳細註釋

LeetCode題解:劍指 Offer 40. 最小的k個數,二叉堆,JavaScript,詳細註釋

技術標籤:LeetCode

原題連結:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/

解題思路:

  1. 該題可使用解決,利用了堆能夠快速插入和取出元素,並始終能夠按要求排序的特點。
  2. 使用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; } }