1. 链表,常见的有单链表,双向链表,循环链表
2. 双向链表是常见的空间换时间的策略
3. 淘汰缓存的做法一般有几个,一般用链表结构,常见的策略有三种:先进先出策略 FIFO(First In,First Out)、最少使用策略 LFU(Least Frequently Used)、最近最少使用策略 LRU(Least Recently Used)。
链表定义
function ListNode(val) {
this.val = val;
this.next = null;
}
4. 常见的链表操作:
链表反转
链表中环的检测
两个有序链表合并
删除链表倒数第n个节点
求链表的中间节点
链表中环的检测
两个有序链表合并
删除链表倒数第n个节点
求链表的中间节点
5. 合并多个链表
function ListNode(val) { this.val = val; this.next = null; } // way1 先找出最小,同时构造 var mergeKLists = function (lists) { if (lists == null || lists.length <= 1) { return lists; } let res = null; let tail = null; while (true) { let isAllNull = true; let curMin = Infinity; let curMinIndex = 0; for (let i = 0; i < lists.length; i++) { if (lists[i] && curMin > lists[i].val) { curMin = lists[i].val; curMinIndex = i; } if (lists[i]) { isAllNull = false; } } if (lists[curMinIndex]) { lists[curMinIndex] = lists[curMinIndex].next; } if (isAllNull) { break; } if (!res) { res = {}; res.val = curMin; res.next = null; } else { let node = new ListNode(curMin); if (res.next === null) { res.next = node; } else { tail.next = node; } tail = node; } } return res; }; var node1 = new ListNode(1); var node3 = new ListNode(3); node1.next = node3; var node2 = new ListNode(2); var node4 = new ListNode(4); var node5 = new ListNode(5); node2.next = node4; node4.next = node5; console.log(mergeKLists([node1, node2])); //way2 先合并,排序,最后生成 var mergeKLists = function (lists) { if (!lists || lists.length == 0) return null; let arr = []; debugger; let res = new ListNode(0); lists.forEach(list => { let cur = list; while (cur) { arr.push(cur.val); cur = cur.next; } }); let cur = res; arr .sort((a, b) => a - b) .forEach(val => { let node = new ListNode(val); cur.next = node; cur = cur.next; }); return res.next; };
6. 检测链表是否有环?
a. 散列表记录
var hasCycle = function(head) { let vistedSet = new Set(); while(head != null){ if(vistedSet.has(head.val)){ return true; }else{ vistedSet.add(head.val); head = head.next; } } return false; };
b. 快指针一次走2步,慢指针一次走一步,如果慢能在某个时刻追到快指针,就说明有环,如果快指针走到了null,说明没有环。
var hasCycle = (head) => { let fastP = head; let slowP = head; while (fastP) { // 快指针指向真实节点 if (fastP.next == null) return false; // 如果下一个为null,说明没有环 slowP = slowP.next; // 慢的走一步 fastP = fastP.next.next; // 快的走两步 if (slowP == fastP) return true; // 快慢指针相遇,有环 } return false; // fastP指向null了,也始终不相遇 }