「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」
前言
如果你经常在力扣刷算法题,并且如果你是一名前端开发者,或许你会使用Javascript来做题,Javascript或许不像C++或Java有一些已经封装好的数据结构,比如栈,队列,可能都需要手动去实现。其实很多人还不知道力扣其实提供了一些轮子供我们使用。
- 这个地方比较隐蔽点击以后
- 出现的提示框告诉我们,力扣已经内置了一个lodash.js的库,这个应该大家比较熟悉的库,就不多赘述了。
- 重点来说说第二个优先队列
堆与优先队列
说到优先队列就不得不先说一下堆的概念
堆
- 百度百科:堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
- 堆又可分为大顶(根)堆和小顶(根)堆
- 以大顶堆为例:对于任意一个结点,都要求根的值 大于或等于 其所有子树结点的值,小顶对则与其相反
优先队列
- 百度百科:普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆数据结构来实现。
- 在Javascript中堆的概念可以用数组实现,关于如何自己手动实现一个堆,将在后序单独写一篇文章。
- 关于如何使用,力扣提供的priority-queue 文档写的已经比较详细
堆-优先队列的作用
一句话:堆适合维护:集合最值
实操力扣算法题
废话不多说,直接来看一道力扣的困难题 23. 合并K个升序链表
- 分析
如果使用暴力解法,每次都需要遍历一次数组,得到头节点最小的链表,然后把这个值插入到新链表最后,然后再去掉这个头再将链表放回数组中,再循环进行查找,这样不出意外力扣判题是会超时的
如果使用优先队列,每次循环都可以从队首得到头节点最小的那个链表元素,如果所有链表的长度总和为k,则算法的空间复杂度为O(k)
- 代码实现
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode[]} lists
* @return {ListNode}
*/
var mergeKLists = function(lists) {
var heap = new MinPriorityQueue({ // 小顶堆
priority: (bid) => bid.val // 堆顶为头节点最小的那个链表
})
// 依次入堆
for(var list of lists) {
if(!list) continue
heap.enqueue(list)
}
var ret = new ListNode() //虚拟头节点,方便返回
var p = ret // 指针
// 每次从堆顶拿出一个链表,将头节点拿出来链接到新链表最后,然后再塞回堆中
while(heap.size()) {
var cur = heap.dequeue().element // 弹出堆顶元素
p.next = cur
p = p.next
if(cur.next) heap.enqueue(cur.next) //如果链表还没走到最后,再塞回堆中
}
p.next = null //链表最后指向null
return ret.next
};
复制代码
--- end ---