牛客网-C++剑指offer-第三十六题(两个链表的第一个公共结点)

题目描述

输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

 

解题思路:

1.分别计算两个链表的长度,看那个长,先走两者长度之差。然后一起走,直到走到第一个相同结点为止,返回;

2.两条相交的链表呈Y型。可以从两条链表尾部同时出发,最后一个相同的结点就是链表的第一个相同的结点。可以利用栈来实现。(但是实现上好像有点问题,每通过)

 

参考代码:

#include <iostream>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include<algorithm>
#include <string>

using namespace std;


struct ListNode {
	int val;
	struct ListNode *next;
};

//第一种思路
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
            if (pHead1 == NULL || pHead2 == NULL)
            {
                return NULL;
            }

            int length1 = count_step(pHead1);
            int length2 = count_step(pHead2);

            if (length1 > length2)
            {
                pHead1 = walk_step( pHead1, length1 - length2);
            } else{
                pHead2 = walk_step( pHead2, length2 - length1);
            }

        while(pHead1 != NULL)
        {

            if (pHead1 == pHead2) return pHead1;
            pHead1 = pHead1->next;
            pHead2 = pHead2->next;
        }

        return NULL;

    }

    int count_step(ListNode* my_head)
    {
        if (my_head == NULL)
            return 0;
        int sum = 0;

        while (my_head)
        {
            sum++;
            my_head = my_head->next;
        }
        return sum;
    }

    ListNode* walk_step(ListNode* my_head, int step)
    {
        if (my_head == NULL)
            return NULL;

        while (step)
        {
            my_head = my_head->next;
            step--;
        }

        return my_head;
    }
};

//第二种思路
//class Solution {
//public:
//    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
//
//        stack<ListNode*> my_pHead1;
//        stack<ListNode*> my_pHead2;
//
//        if (pHead1 == NULL || pHead2 == NULL)
//            return NULL;
//
//        while (pHead1)
//        {
//            my_pHead1.push(pHead1);
//            pHead1 = pHead1->next;
//        }
//
//        while (pHead2)
//        {
//            my_pHead2.push(pHead2);
//            pHead2 = pHead2->next;
//        }
//
//        ListNode* res;
//
//        while (!my_pHead1.empty() && !my_pHead2.empty())
//        {
//            if (my_pHead1.top() == my_pHead2.top())
//            {
//                res = my_pHead1.top();
//                cout<<res->val<<endl;
//            } else{
//                break;
//            }
//
//            my_pHead1.pop();
//            my_pHead2.pop();
//
//        }
//        cout<<"res:"<<res->val<<endl;
//        return NULL;
//    }
//};

int main()
{
    Solution solution;

    ListNode p1;
    ListNode p2;
    ListNode p3;

    ListNode p12;
    ListNode p11;

    ListNode p23;
    ListNode p22;
    ListNode p21;

    p21 = {21,&p22};
    p22 = {22,&p23};
    p23 = {23,&p3};

    p11 = {11,&p12};
    p12 = {12,&p3};

    p3 = {3,&p2};
    p2 = {2,&p1};
    p1 = {1,NULL};

    ListNode* my_phead1 = &p21;
    ListNode* my_phead2 = &p11;

    solution.FindFirstCommonNode(my_phead1,my_phead2);

    return 0;
}

 

### 找到两个链表第一个公共节点 #### 方法一:哈希集合 (基于引用[^1]) 通过使用 `Map` 或者 `Set` 数据结构来存储其中一个链表的所有节点。随后遍历另一个链表,检查当前节点是否已经存在于集合中。如果存在,则该节点即为两链表第一个公共节点。 这种方法的时间复杂度为 \(O(m+n)\),其中 \(m\) 和 \(n\) 是两条链表的长度;空间复杂度为 \(O(m)\) 或 \(O(n)\),取决于哪个链表被存入集合中。 ```python def getIntersectionNode(headA, headB): nodes_in_B = set() current_node = headB while current_node is not None: nodes_in_B.add(current_node) current_node = current_node.next current_node = headA while current_node is not None: if current_node in nodes_in_B: return current_node current_node = current_node.next return None ``` --- #### 方法二:双指针法 (基于引用[^2]) 定义两个指针分别指向两个链表头结点。每次移动一步,当到达链表末端时,跳转至另一条链表头部继续前进。这样可以消除两者之间的长度差,在第二次相遇处即是第一个公共节点。 此方法时间复杂度同样为 \(O(m+n)\),而空间复杂度降为了 \(O(1)\)。 ```python def getIntersectionNode(headA, headB): pointerA, pointerB = headA, headB while pointerA != pointerB: pointerA = headB if pointerA is None else pointerA.next pointerB = headA if pointerB is None else pointerB.next return pointerA # 返回值可能是公共节点或者None ``` --- #### 方法三:计算长度差异并调整起始位置 先遍历两条链表得到它们各自的长度,并求出差值。让较长的那个链表先行走这个差距步数后再同步逐一遍历比较各对应节点直至发现相等为止。 这种方式也实现了线性时间和常量级额外内存消耗的目标。 ```python def length(node): count = 0 while node: count += 1 node = node.next return count def getIntersectionNode(headA, headB): lenA, lenB = length(headA), length(headB) shorter = headA if lenA < lenB else headB longer = headB if lenA < lenB else headA diff = abs(lenA - lenB) for _ in range(diff): longer = longer.next while shorter and longer: if shorter == longer: return shorter shorter = shorter.next longer = longer.next return None ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值