剑指offer-两个链表的第一个公共节点(c++ 三种方法)

本文介绍了三种方法找到两个链表的第一个公共节点:1) 使用map存储第一个链表节点;2) 比较链表长度并同步遍历;3) 利用双指针技巧。每种方法都有详细的代码实现。
摘要由CSDN通过智能技术生成

两个链表的第一个公共节点

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

题解:
阵对这个题目有三种解法:
1)map法:
将第一个链表的所有节点都保存进入map中,然后然后对第二个链表进行查找,观察是否存在在map中,若存在,则输入该节点。
代码如下:

/*
struct ListNode {
 int val;
 struct ListNode *next;
 ListNode(int x) :
   val(x), next(NULL) {
 }
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if(!pHead1||!pHead2) return NULL;
        map<ListNode*,int> mp;
        while(pHead1){
            mp[pHead1]=pHead1->val;
            pHead1=pHead1->next;
        }
        while(pHead2){
            if(mp.find(pHead2)!=mp.end())
                break;
            pHead2=pHead2->next;
        }
        return pHead2;
  }
};

2)链表长度法:
如果两个链表有公共节点,那么其重合节点后的长度是一样的。
因此,可经历两次遍历,分别得到两个链表的长度。
比较二者的长短,对长的链表进行遍历,等长链表剩下的节点数与短链表的节点数相等时,同时进行遍历,比较两链表的节点是否相等。
代码如下:

/*
struct ListNode {
 int val;
 struct ListNode *next;
 ListNode(int x) :
   val(x), next(NULL) {
 }
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        /*if(!pHead1||!pHead2) return NULL;
        map<ListNode*,int> mp;
        while(pHead1){
            mp[pHead1]=pHead1->val;
            pHead1=pHead1->next;
        }
        while(pHead2){
            if(mp.find(pHead2)!=mp.end())
                break;
            pHead2=pHead2->next;
        }
        return pHead2;*/
        if(!pHead1||!pHead2) return NULL;
        int len1=0,len2=0;
        ListNode *p,*q;
        p=pHead1;q=pHead2;//用以遍历长度后,重新更新头节点
        while(pHead1){//计算链表1的长度
            len1++;
            pHead1=pHead1->next;
        }
        while(pHead2){//链表2的长度
            len2++;
            pHead2=pHead2->next;
        }
        if(len1>len2){
            int len=len1-len2;
            for(int i=0;i<len;i++)
                p=p->next;//遍历长链表长于短链表的节点
        }
        else{
            int len=len2-len1;
            for(int i=0;i<len;i++)
                q=q->next;
        }
        while(p){//两个链表同时遍历节点
            if(p==q)
                return p;
            q=q->next;
            p=p->next;
        }
        return NULL;
    }
};

3)双指针法:
假设链表1长度为a+n,链表2的长度为b+n(a>b)。利用两个指针同时遍历两个链表,当链表2遍历完后,链表1所处的节点位置为b+n,剩余节点为a-b。将遍历完链表2的指针指向1,需要走b+n+a。而指向a链表的指针遍历完a链表时,指向b的头节点,则走到相同节点,需要走a+b+n。此时,双指针指向重合的第一个节点。

代码如下:

/*
struct ListNode {
 int val;
 struct ListNode *next;
 ListNode(int x) :
   val(x), next(NULL) {
 }
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        /*if(!pHead1||!pHead2) return NULL;
        map<ListNode*,int> mp;
        while(pHead1){
            mp[pHead1]=pHead1->val;
            pHead1=pHead1->next;
        }
        while(pHead2){
            if(mp.find(pHead2)!=mp.end())
                break;
            pHead2=pHead2->next;
        }
        return pHead2;*/
        /*if(!pHead1||!pHead2) return NULL;
        int len1=0,len2=0;
        ListNode *p,*q;
        p=pHead1;q=pHead2;
        while(pHead1){
            len1++;
            pHead1=pHead1->next;
        }
        while(pHead2){
            len2++;
            pHead2=pHead2->next;
        }
        if(len1>len2){
            int len=len1-len2;
            for(int i=0;i<len;i++)
                p=p->next;
        }
        else{
            int len=len2-len1;
            for(int i=0;i<len;i++)
                q=q->next;
        }
        while(p){
            if(p==q)
                return p;
            q=q->next;
            p=p->next;
        }
        return NULL;*/
        if(!pHead1||!pHead2) return NULL;
        ListNode *p,*q;
        p=pHead1;
        q=pHead2;
        while(p!=q){
            if(p) p=p->next;
            if(q) q=q->next;
            if(p!=q){
                if(!p) p=pHead2;
                if(!q) q=pHead1;
            }
        }
        return p;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值