链表✅
链表设计的核心知识点包括
- 基本结构
- 哨兵节点使用
- 快慢指针
- 多指针操作
数组转换为链表?
// 实现 arrayToList 函数,将数组转换为链表
// 输入:[1, 2, 3, 4, 5]
// 输出:{ value: 1, next: { value: 2, next: { value: 3, next: { value: 4, next: { value: 5, next: null } } } } }
function arrayToList (arr) {
}
答案
Tests
单向链表结构实现?
// 实现链表类,支持如下核心方法
// 节点
interface Node {
value: number
next: Node | null
}
// 链表
abstract class LinkedList {
constructor(values: number[]): LinkedList // 构造函数,接收一个数组作为参数,将数组转换为链表
add(value: any):void // 往链表末尾添加节点
delete(value: any):void // 删除值为 value 的节点
deleteValues(values: any[]):void // 批量删除,删除值在 values 数组中的节点
find(value: any):Node | null // 查找值为 value 的节点
head:Node | null // 获取链表头节点
tail:Node | null // 获取链表尾节点
}
答案
Tests
合并两个有序链表
/**
* 合并两个有序链表
* 输入:l1 = [1,2,4], l2 = [1,3,4]
* 输出:[1,1,2,3,4,4]
*/
function mergeLinkedList (l1, l2) {
}
答案
Tests
删除存在重复值的节点
/**
* 删除链表中重复的元素
* 输入:[1, 1, 2, 3, 3]
* 输出:[2, 3]
*/
function removeDuplicate (head) {
}
答案
Tests
删除倒数第 n 个节点
/**
* 删除链表的倒数第 n 个节点
* 输入:[1, 2, 3, 4, 5], n = 2
* 输出:[1, 2, 3, 5]
*/
function removeNthFromEnd (head, n) {
}
答案
Tests
翻转链表
// 反转链表 时间复杂度 O(n),空间复杂度 O(1)
// 输入:[1, 2, 3, 4]
// 输出:[4, 3, 2, 1]
function reverseList (head) {
}
答案
Tests
k 接翻转链表
/**
* K 个一组翻转链表
* 输入:[1, 2, 3, 4, 5], k = 2
* 输出:[2, 1, 4, 3, 5]
*/
function reverseKGroup (head, k) {
}
判断单向链表是否是循环链表
/**
* 判断是否有环
*/
function cycleCheck (head) {
}
答案
Tests
判断单向链表是否是循环链表
function isCyclicLinkedList (head) {
if (!head) {
return false
}
let slow = head
let fast = head
while (fast && fast.next) {
slow = slow.next
fast = fast.next.next
if (slow === fast) {
return true
}
}
return false
}
定位环起点
跳表的原理和应用
-
原理:
- 多层链表结构
- 每层是下层的子集
- 类似二分查找的思想
-
应用:
- Redis的有序集合
- 替代平衡树的场景
-
时间复杂度:平均O(logN)
ugly-num 变体
应该算是一道easy-medium,给定一个数组,只有一个初始数字1,对这个数组的每个数字K,做k*2+1和k*3+1,然后加入数组,要求这个数组是sorted并且没有重复元素,返回第N个这个数组应该是[1,3,4,7,9,10,13,..]
算法
3(1*2+1),4(1*3+1)
7(3*2+1),10(3*3+1)
9(4*2+1), 13(4*3+1)
因为出现了3算出来的比4还大,所以单纯用queue不行,要用heap,然后用set去重分析了时间