反转链表
当输入1 -> 2 -> 3 -> 4 -> null链表时,能够返回null <- 1 <- 2 <- 3 <- 4.参见Leetcode 206
只传入一个头指针,希望返回反转链表后的头指针。
思路,从头指针开始一个个反转。需要保存prev,curr,next三个指针,否则会断
const reverseList = function(head) {
let prev = null; // 最后一个指针为null
let curr = head; // 从头指针开始
while (curr) {
let next = curr.next; // 保存next结点,不保存的话当改变了curr.next之后就找不到next结点了
curr.next = prev; // 改变当前元素的next,例如头指针的next改为了null
prev = curr; // 移动上一节点,为修改下一个节点的next做准备
curr = next; // 修改完了,去下一个结点修改
}
return prev // 原链表最后一个为null,所以返回prev,反转的最后一个
}
检测链表是否有环
leetcode 141
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
解法,利用快慢指针,原理是例如两个人跑步,如果跑圆形操场,快的人速度是慢的人两倍。慢的人跑完一圈,快的人跑了2圈,他们在中间肯定会相遇。如果不是圆形操场,那么他们永远也不会相遇。
const hasCycle = function(head) {
let first = head; // 同一起跑点
let second = head; // 同一起跑点
while(first && second && second.next) {
first = first.next;
second = second.next.next;
if(p1 === p2) {
return true
}
}
return false
}
合并两个有序链表
leetcode 21
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
function mergeTwoLists(l1, l2) {
if(l1 === null) {
return l1
}
if(l2 === null) {
return l2
}
if(l1.val < l2.val) { // 判断哪个值更小
l1.next = mergeTwoLists(l1.next, l2)
return l1
} else {
l2.next = mergeTwoLists(l1, l2.next)
return l2
}
}
删除链表的倒数第 N 个结点
leetcode 19
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
思路: 利用快慢指针
- 定义两个指针,一个先走N步,一个从头开始
- 这样的话,快指针走到最后,快指针距离慢指针一定是相差N步,慢指针就站在了要删除的元素上
- 但是链表删除某个要用到它前、后两个结点。所以快指针走N+1步,让慢指针少走一步,刚好停在要删除元素的前一个结点
虚拟头结点
链表中,删除头结点跟删除其它结点是不一样的,因为头结点没有前驱。可以通过增加一个虚拟头结点来统一头结点和其它结点的删除方式。
function removeNthFromEnd(head, n) {
let dummyNode = new ListNode(0, head); // 虚拟头结点
let fast = dummyNode;
let slow = dummyNode;
while(n + 1 > 0) {
n--;
fast = fast.next // 快指针走 n + 1步
}
while(fast) { // 两个指针一起走,直到快指针走到最后
fast = fast.next;
slow = slow.next
}
let next = slow.next.next;
slow.next = next;
return dummyNode.next // 返回头结点
}
返回链表的中间结点
leetcode 876
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
解题思路:快慢指针
- 定义两个指针,一个一次走两步,一个一次走一步
- 当快指针走到了最后,慢指针一定是走了一半
var middleNode = function (head) {
let fast = head;
let slow = head;
while (fast && fast.next) {
fast = fast.next.next;
slow = slow.next
}
return slow
};
- 两种情况:
- 快指针走到了最后是null,这样链表中间结点就是双数。直接返回慢指针
- 快指针的next是null,这样链表中间结点就是单数。直接返回慢指针