剑指offer_t36_两个链表的公共节点

在这里插入图片描述
首先明确公共节点的定义,即两个链表从某一节点开始,他们的next指针都指向同一个节点。

方法1,暴力穷举

  看到这题的第一个思路,就是直接遍历,类似双层for循环,依次比较链表1和链表2每个节点,看有没有公共节点节点。思路比较简单,但时间复杂度高,为Olog(n^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 nullptr;
        ListNode * p1= pHead1;
        ListNode * p2= pHead2;
        while(p1)
        {
            while(p2)
            {
                if(p1 == p2)
                {   
                    return p2;
                }
                else
                {
                    p2=p2->next;
                }
            }
            p2 = pHead2;
            p1=p1->next;
        }
        return nullptr;
    }
};
方法2,栈方法

  如果两个链表有公共节点,那么一定是一个型,即从链表最后,到第一个公共节点为止,其间所有节点都是一样的。因此可以利用栈先入后出特性,把两个链表存入栈中,再pop出来,从后向前遍历,直到两个栈的栈顶元素不相等,则说明第一个公共节点在该位置的后面一个。但这种方法空间复杂度比较高

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if(!pHead1 || !pHead2) return nullptr;
        stack<ListNode*> s1;
        stack<ListNode*> s2;
        ListNode * p1 = pHead1;
        ListNode * p2 = pHead2;
        while(p1)
        {    
            s1.push(p1);
            p1 = p1->next;
        }
        while(p2)
        {
            s2.push(p2);
            p2 = p2->next;
        }
        
        int temp = 0;
        int size_1 = s1.size();
        while(!s1.empty()&&!s2.empty())
        {
            if(s1.top()!=s2.top())
                break;
            else 
            {    s1.pop();
                 s2.pop();
                 temp++;
            }
        }
        temp = size_1-temp;
        ListNode *res = pHead1;
        while(temp--)
        {
            res = res->next;
        }
        return res;
    }
};
方法3,双指针

分析两个含有公共节点链表的结构,易知,
  如果令两个链表长度相等,那么定义两个指针p1和p2,分别指向链表1和链表2头节点,两个指针同时开始向链表尾部移动,直到出现第一个相同的节点,就为公共节点。
  如果两个链表长度不等,我们可以求出两个链表的长度差为s,然后令长链表先走s步,那么长链表剩下的节点数就和短链表的一样了,就可以同上了。

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if(!pHead1||!pHead2)    return nullptr;
        ListNode *p1 = pHead1;
        ListNode *p2 = pHead2;
        int count1 = 0;
        int count2 = 0;
        int sub = 0;
        while(p1){
            p1=p1->next;
            count1++;
        }
        while(p2){
            p2=p2->next;
            count2++;
        } //以上为求长度
        
        if(count1 > count2)
        {
            sub = count1-count2;
            while(sub--)
            {
                pHead1=pHead1->next;
            }
        }
        else
        {
            sub = count2-count1;
            while(sub--)
            {
                pHead2=pHead2->next;
            }
            
        }
        //以上代码让长链表先走sub步
        while(pHead1!=pHead2)
        {
            pHead1=pHead1->next;
            pHead2=pHead2->next;
        }//以上为找出第一个相同节点
        return pHead1;
    }
};
方法4 双指针相遇

原理还没搞清楚,先放上链接记录一下
图解 双指针法,浪漫相遇

方法5 使用stl map

思路:将第一个链表的元素都存入map中,然后利用第二个链表作为key,在map中查找是否有相同元素,有则返回该节点

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
         if(!pHead1 || !pHead2) return nullptr;
         map<ListNode*,int> m;
         while(pHead1)
         {
            m[pHead1] = pHead1->val;
            pHead1 = pHead1->next;
         }
         while(pHead2)
         {
             if(m.find(pHead2)!= m.end())
                 return pHead2;
             else
                 pHead2 = pHead2->next;
         }
         return nullptr;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

通信仿真爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值