24. 两两交换链表中的节点
定好边界条件,用递归法解决
function swapPairs(head: ListNode | null): ListNode | null {
return swap(head, head ? head.next : null)
};
function swap(n1: ListNode | null, n2: ListNode | null) {
if (!n1) {
return null
}
if (!n2) {
return n1
}
n1.next = swap(n2.next, n2.next ? n2.next.next : null)
n2.next = n1
return n2
}
19. 删除链表的倒数第 N 个结点
经典快慢指针,创建虚拟头结点,让fast指针从虚拟头结点移动n+1步,然后让slow指针从虚拟头结点开始移动,当fast指向null时,slow指向的就是待删除节点的前一个节点
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
const dummyHead: ListNode = { val: 0, next: head }
let fast = dummyHead
let slow = dummyHead
for (let i = 0; i <= n; i++) {
fast = fast.next
}
while (fast) {
fast = fast.next
slow = slow.next
}
slow.next = slow.next.next
return dummyHead.next
};
面试题 02.07. 链表相交
先从长链表的头结点开始向后移动,移动到某个节点,使得长链表剩余长度等于短链表的长度,这时同时向后移动两个链表指针,判断节点指针是否相等,要注意的是判断指针而不是值是否相等
var getIntersectionNode = function (headA, headB) {
let lenA = 0
let lenB = 0
let tmpA = headA
let tmpB = headB
while (tmpA) {
lenA++
tmpA = tmpA.next
}
while (tmpB) {
lenB++
tmpB = tmpB.next
}
let curA = headA
let curB = headB
if (lenA > lenB) {
let diff = lenA - lenB
for (let i = 0; i < diff; i++) {
curA = curA.next
}
} else {
let diff = lenB - lenA
for (let i = 0; i < diff; i++) {
curB = curB.next
}
}
while (curA && curB) {
if (curA === curB) {
return curA
}
curA = curA.next
curB = curB.next
}
return null
};
142. 环形链表 II
环形链表比较复杂,还是要多看卡哥解析
整体思路是使用fast和slow指针,fast每次走2个节点,那么fast和slow一定会在环内相遇,并且相遇时slow一定是第一次入环,这样根据相遇时fast和slow走的步数就能计算环的入口
function detectCycle(head: ListNode | null): ListNode | null {
let fast = head
let slow = head
while (fast && fast.next) {
fast = fast.next.next
slow = slow.next
if (fast === slow) {
let ret = head
while (ret !== fast) {
fast = fast.next
ret = ret.next
}
return ret
}
}
return null
};