【每日算法0222】双指针(简单)

67 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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 个节点。

image-20230221171814906

分析

双指针问题的一个常见场景,找到两个节点相遇的地方

解决方法更偏向一个数学问题,如何让同时出发的两个节点,在链路上的某个节点,走过相同的路程

为什么需要走过相同的路程?因为走过相同的路程,意味着在那一刻,两个节点刚好相遇了

由图示分析:

  • 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
};