挑战刷leetcode第六天( 链表-相交链表)

112 阅读3分钟

在日常的算法面试中,链表相关的问题总是频繁出现。而链表相交问题更是其中的经典之一。想象一下,你面前有两条链表,它们在某一点相交,然后合并成一条链表。如何高效地找到这个交点?今天,我们将通过Java和C++两种语言的实现,深入探讨这个问题的解决思路,并揭示其中的巧妙之处。

1. 问题描述

给定两个单链表 headA 和 headB,判断它们是否相交,并返回相交的节点。如果两个链表没有交点,则返回 null

注意:

  • 链表相交指的是两个链表在某个节点之后完全重合,而不是仅仅值相同。
  • 链表的结构在相交之后必须完全一致。

2. 直观解法:暴力遍历

最直观的解法是使用双重循环,遍历链表A的每一个节点,同时遍历链表B的每一个节点,判断是否有相同的节点。这种方法的时间复杂度为O(m*n),其中m和n分别是链表A和链表B的长度。显然,这种方法的效率较低,尤其是在链表较长时。

3. 优化思路:双指针法

为了优化时间复杂度,我们可以使用双指针法。这种方法的核心思想是让两个指针分别遍历两个链表,当其中一个指针到达链表末尾时,将其指向另一个链表的头节点。这样,两个指针最终会在相交节点相遇,或者同时到达链表末尾(表示没有交点)。

java代码
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }

        ListNode ha = headA;
        ListNode hb = headB;
        while (ha != hb) {
            ha = ha != null ? ha.next : headB;
            hb = hb != null ? hb.next : headA;
        }
        return ha;
    }
C++代码
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        if (headA == nullptr || headB == nullptr) {
            return nullptr;
        }

        ListNode* ha = headA;
        ListNode* hb = headB;
        while (ha != hb) {
            ha = ha != nullptr ? ha->next : headB;
            hb = hb != nullptr ? hb->next : headA;
        }
        return ha;
    }

4. 为什么双指针法有效?

双指针法的关键在于消除两个链表的长度差。假设链表A的长度为m,链表B的长度为n,且它们的相交部分长度为k。当两个指针分别遍历完自己的链表后,切换到另一个链表的头节点,相当于让两个指针都走了m + n - k步。这样,它们最终会在相交节点相遇。

举例说明:

  • 链表A: 1 -> 2 -> 3 -> 4 -> 5
  • 链表B: 6 -> 7 -> 4 -> 5
  • 相交节点为 4

指针ha的遍历路径:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 4
指针hb的遍历路径:6 -> 7 -> 4 -> 5 -> 1 -> 2 -> 3 -> 4
最终,两个指针在节点 4 处相遇。

5. 时间复杂度与空间复杂度

  • 时间复杂度:O(m + n),其中m和n分别是链表A和链表B的长度。两个指针最多遍历m + n个节点。
  • 空间复杂度:O(1),只使用了常数级别的额外空间。

6. 总结

链表相交问题是一个经典的算法问题,通过双指针法,我们可以高效地找到两个链表的交点。这种方法不仅时间复杂度低,而且代码简洁易懂。理解其背后的原理,可以帮助我们在面对类似问题时,快速找到解决方案。

在未来的学习中,我们将继续探索更多有趣的算法问题,挑战自我,不断提升。希望今天的分享能为你带来新的启发,也欢迎你在评论区分享你的想法和疑问。

坚持打卡,持续进步!希望友友们监督哈!