剑指 Offer 06. 从尾到头打印链表
方法一 递归
递归法,先递归至链表末端;回溯时,依次将节点值加入数组;
递归解析:
- 终止条件:
head = null; - 递推工作:访问下一个节点
head.next - 回溯工作:将当前节点的值加入数组;
复杂度分析
- 时间复杂度O(N):遍历链表,递归N次;
- 空间复杂度O(N):系统递归需要O(N)的栈控件
var reversePrint = function(head) {
const res = [];
helper(head, res);
return res;
};
var helper = function(head, res) {
if (head === null) {
return;
}
helper(head.next, res);//递归过程
res.push(head.val);//回溯过程
}
方法二 辅助栈法
辅助栈法:借用栈的后进先出(LIFO)特性;
算法流程:
- 入栈:遍历链表,将各个节点值入栈
- 出栈:将各节点pop出栈,存储数组并返回
复杂度分析
- 时间复杂度O(N):入栈和出栈共使用O(N)时间
- 空间复杂度O(N):辅助栈和数组共使用O(N)的额外空间
var reversePrint = function(head) {
const stack = [];
let curr = head;
while (curr) {
stack.push(curr.val);
curr = curr.next;
}
const res = [];
while (stack.length !== 0) {
res.push(stack.pop())
}
return res;
};
剑指 Offer 24. 反转链表
方法一 迭代(双指针)
遍历链表,并在访问各链表时修改next指向;
算法流程:
- 定义cur、prev
- 遍历链表,记cur.next为next,将当前cur.next 指向prev
- prev = cur、cur = next;
复杂度分析:
- 时间复杂度O(N):遍历链表使用线性大小时间;
- 空间复杂度O(1):变量 pre 和 cur 使用常数大小额外空间。
var reverseList = function(head) {
let cur = head, prev = null;
while (cur) {
let next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
方法二 递归
使用递归法遍历链表,当越过尾节点后终止递归,在回溯时修改各节点的next引用指向
recur(cur, pre) 递归函数:
- 终止条件:cur为空,返回prev节点,终止递归
- 递归后继节点:记录返回值,即反转链表的头节点为res;
- 修改当前节点cur引用指向前驱节点prev;
- 返回反转链表的头节点res
复杂度分析:
- 时间复杂度O(N):遍历链表使用线性大小的时间
- 空间复杂度O(N):遍历链表的递归深度达到N,系统使用O(N)大小额外空间;
var reverseList = function(head) {
return recur(head, null);
}
var recur = function(cur, prev) {
//递归终止条件
if (cur === null) {
return prev;
}
let res = recur(cur.next, cur);
cur.next = prev;
return res;
}
剑指 Offer 35. 复杂链表的复制
复制链表很简单,本体难点在于random节点的指向。
方法一 借用哈希map
利用哈希表,构建原链表节点和新链表对应节点的键值映射关系,在遍历构建新链表的各节点的的next 和 random的引用指向;
算法流程
- 若头节点为空,返回null;
- 初始化:哈希表map,节点cur指向head
- 复制链表:建立新链表,并向map添加键值对(老节点是键,新节点是值);cur 遍历至原链表下一节点;
- 构建新链表的引用指向:构建新节点的
next和random指向;cur 遍历至原链表下一节点; - 返回值:新链表的头节点
map(head)
function copyRandomList(head) {
if (!head) {
return null;
}
let cur = head;
const map = new Map();
while (cur) {
map.set(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
while (cur) {
map.get(cur).next = cur.next ? map.get(cur.next) : null;
map.get(cur).random = cur.random ? map.get(cur.random) : null;
cur = cur.next;
}
return map.get(head);
}