开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 14 天,点击查看活动详情
题目
剑指 Offer 25. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
分析一
本题直观想法可以使用迭代对比头节点来组装我们的最终结果
- 初始化伪头节点
- 迭代遍历 l1 和 l2 各节点
- 比对l1 和 l2 值的大小
将伪头节点指向值小的节点,如果其中一个节点遍历完,直接连接剩余节点并返回
实现
function mergeTwoLists(l1: ListNode | null, l2: ListNode | null): ListNode | null {
let head = new ListNode()
let node = head
while (l1 || l2) {
if (l1 && l2) {
// 比较
if (l1.val > l2.val) {
node.next = l2
l2 = l2.next
} else {
node.next = l1
l1 = l1.next
}
}
else if (l1) {
node.next = l1
return head.next
}
else if (l2) {
node.next = l2
return head.next
}
node = node.next
}
return head.next
};
分析二
另一个思路,利用题目的方法使用迭代
- 确定边界条件
当其中任意节点不存在时跳出递归
- 确定返回值
返回当前两个节点中较小的那个节点
- 确定递归体逻辑
比对两节点值的大小
将较小的那个值指向新一轮的迭代返回值
最后返回较小的那个值,最终处理完的结果就是题目所求
function mergeTwoLists(l1: ListNode | null, l2: ListNode | null): ListNode | null {
if (!l1) {
return l2
}
if (!l2) {
return l1
}
if (l1.val >= l2.val) {
l2.next = mergeTwoLists(l1, l2.next)
return l2
} else {
l1.next = mergeTwoLists(l1.next, l2)
return l1
}
};
题目
剑指 Offer 52. 两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共节点。
示例:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
分析
双指针问题的一个常见场景,找到两个节点相遇的地方
解决方法更偏向一个数学问题,如何让同时出发的两个节点,在链路上的某个节点,走过相同的路程
为什么需要走过相同的路程?因为走过相同的路程,意味着在那一刻,两个节点刚好相遇了
由图示分析:
- A出发,到尾部转向B,总路程是:5 + 3 = 8
- B出发,到尾部转向A,总路程是:6 + 2 = 8
- 走8步之后,两个指针就会开始同步遍历
- 取出第一个相同的点,即为该题所求
实现
var getIntersectionNode = function(headA, headB) {
if (!headA || !headB) return null
let A = headA
let B = headB
while (A != B) {
A = A == null ? headB : A.next
B = B == null ? headA : B.next
}
return A
};