[leetcode]Intersection of Two Linked Lists寻找两链表的公共节点

本文介绍了一种在两个单链表中找到它们开始相交节点的有效算法。此算法能在O(n)时间内完成,并且仅使用O(1)的额外空间。文章详细解释了如何根据链表长度调整遍历起点,以便于比较两个链表并找出首个公共节点。

Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists:

A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3

begin to intersect at node c1.

Notes:
If the two linked lists have no intersection at all, return null.
The linked lists must retain their original structure after the function returns.
You may assume there are no cycles anywhere in the entire linked structure.
Your code should preferably run in O(n) time and use only O(1) memory.
题目意思:求两链表的第一个公共节点出现的位置,并把该位置的节点返回。
notes:
如果两个链表根本没有交集,返回null。
链表函数返回后,保留其原有的结构返回。
你可以假设没有循环在整个地方的连接结构。
您的代码应该优选地运行在O(n)时间和O(1)的存储。
解题思路:
1. 把链表变换为反向链表,通过比较最后两个链表的节点值的不同来搜索出第一个公共节点,但与题目给出的要求“保留原有结构不符”
2. 若两个链表的最后一个元素相等,则这两个链表一定存在公共节点,也许公共节点是最后第二个,也许是链表中间的某一个节点,让长的链表先移动abs(sizeA-sizeB)距离,让headA与headB的长度一致,这样就容易比较两个链表并寻的第一个公共节点。
如下为思路2的C代码,比较冗余:

/**
 * 解题思路:headA与headB的链表长度有三种情况,1. headA长度比headB长 2. headA长度比headB短  3.headA的长度 == headB的长度
 * 若两个链表的最后一个元素ListNODE是相等的,说明这两个链表一定相等,只是不清楚相等的第一个元素在链表的那个位置
 *所以我们可以采取如下思路:长的链表先移动abs(sizeA-sizeB)个节点,这样headA与headB一样长,就可以进行两链表直接对比
 * 寻找节点相等的公共节点
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {

    int i,sizeA,sizeB;
    int sub = 0;
    struct ListNode *A, *B;
    A = headA;
    B = headB;
    if(headA == NULL || headB == NULL){
        return NULL;
    }
    sizeA = 1;
    while(headA->next != NULL){
        sizeA++;
        headA = headA->next;
    }
    sizeB = 1;
    while(headB->next != NULL){
        sizeB++;
        headB = headB->next;
    }
    if(headA->val == headB->val){
        if(sizeA > sizeB){
            sub = sizeA - sizeB;
            for(i = 0; i < sub; i++){
                A = A->next;
            }
        }else if(sizeA < sizeB){
            sub = sizeB - sizeA;
            for(i = 0; i < sub; i++){
                B = B->next;
            }
        }
        while(A != NULL && B != NULL){
            if(A->val == B->val){
                return A;
            }else{
                A = A->next;
                B = B->next;
            }
        }
    }else{
        return NULL;
    }
}
### LeetCode C++ 实现链表相交问题的解决方案 以下是基于提供的引用以及专业知识设计的一个完整的解决方案。此方案通过计算链表长度差并调整起始位置来找到第一个公共节点。 #### 解决方案概述 为了高效解决该问题,可以采用双指针法,在不改变原结构的情况下完成操作。具体逻辑如下: 1. 计算链表的长度 `lenA` 和 `lenB`。 2. 将较长链表的头指针向前移动者长度之差的距离。 3. 同步遍历链表直到发现相同节点或者到达尾部。 这种方法的时间复杂度为 \(O(m+n)\),空间复杂度为 \(O(1)\)[^3]。 #### 完整代码实现 (C++) ```cpp #include <iostream> using namespace std; // Definition for singly-linked list. struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; class Solution { public: ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) { if (!headA || !headB) return nullptr; // Step 1: Calculate lengths of both lists int lenA = getListLength(headA); int lenB = getListLength(headB); // Step 2: Align the start point by moving longer list's pointer forward while (lenA > lenB) { headA = headA->next; --lenA; } while (lenB > lenA) { headB = headB->next; --lenB; } // Step 3: Traverse both lists together until an intersection is found or end reached while (headA && headB) { if (headA == headB) return headA; // Found intersection headA = headA->next; headB = headB->next; } return nullptr; // No intersection exists } private: int getListLength(ListNode* head) const { int length = 0; while (head) { ++length; head = head->next; } return length; } }; ``` 上述代码实现了寻找个单向链表首个公共节点的功能[^4]。它首先分别获取链表的长度,并让较长的那个先前进几步以使剩余部分等长;接着同步推进直至找到共同节点或结束循环返回空值表示无交叉情况发生[^5]。 #### 关键点解析 - **时间效率**: 整体算法仅需次线性扫描即可得出结论,因此满足题目提出的性能需求即运行时间为\(O(n)\)。 - **空间节省**: 不需要额外存储辅助数据结构,整个过程只用了固定数量变量保存临时状态信息,故达到常数级内存消耗标准\[O(1)]\. ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值