C/C++ BM10 两个链表的第一个公共结点

前言

这道题用到的思想和前几道题一样,涉及到了双指针这种,整体难度不大。


题目

描述
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

数据范围: n ≤ 1000 n≤1000 n1000
要求:空间复杂度 O ( 1 ) O(1) O(1),时间复杂度 O ( n ) O(n) O(n)

例如,输入 1 , 2 , 3 , 4 , 5 , 6 , 7 {1,2,3},{4,5},{6,7} 1,2,3,4,5,6,7时,两个无环的单向链表的结构如下图所示:
在这里插入图片描述

可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。

输入描述:
输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。

返回值描述:
返回传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表。

解决方案一

1.1 思路阐述

这个思路一是不满足题目要求的空间复杂度 O ( 1 ) O(1) O(1),空间复杂度为 O ( n ) O(n) O(n),但是也是AC了的。

这个思路是受BM6的启发

因为找第一个公共节点,所以其实我们要找的是节点的地址而非节点的值。因为节点在内存中的地址是唯一的,我们只要判断节点地址是否出现同样的即可(这个就类似于判断有没有环)。所以我们使用STL的set容器可以很好的做到这一点。

代码里面首先是将一条链表的所有节点放到容器中去,接着在容器中查找 p H e a d 2 pHead2 pHead2的每一个节点。如果找不到,那么 f i n d find find函数会自动返回set容器的最后一个索引位置,所以这里我判断使用的是 m y S e t . e n d ( ) mySet.end() mySet.end()。找不到则将节点加入到set中去,继续遍历下一个节点。

找不到则返回空指针,找到了则表示这个节点就是公共节点。

1.2 源码

#include <iterator>
#include <vector>
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
		std::set<ListNode *> mySet;

		while (pHead1) {
			mySet.insert(pHead1);
			pHead1=pHead1->next;
		}
		
		for (auto it=mySet.begin(); it!=mySet.end();it++) {
			if(!pHead2)
				break;
			if(mySet.find(pHead2)==mySet.end())
			{
				mySet.insert(pHead2);
				pHead2=pHead2->next;
			}
			else {
				return pHead2;
			}			
		}
		return nullptr;
    }
};

解决方案二

2.1 思路阐述

采用双指针法。

这个有点类似于找最小公倍数。

算法流程如下:

使用两个指针分别从两个链表头节点出发
两个指针分别走完当前链表后,再从另一个链表重新开始走,直到相遇
当他们走的步数刚好相等时,两个指针第一次相遇

举个例子,一个链表A长度为5,一个链表B长度为4。它们对应的指针a和b都从链表表头开始按序遍历节点。

假设两个链表存在公共节点,也就是说两个链表指针都会遍历同一个节点。因为是一次遍历一个节点,不是跳着遍历,所以两个链表最终肯定会碰到一起,因为算法中将指针的遍历做了一个循环操作,也就是把单向链表变成了循环链表来遍历。那两个不等长的链表什么时候链表指针走过的节点数会实现等长, 5 ∗ 4 = 20 5*4=20 54=20,也就是说,两个指针走20个节点开始,接下来的节点应该是同样的节点,这不刚好就是第一个公共节点吗。

2.2 源码

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        int len1 = get_ListLength(pHead1);
        int len2 = get_ListLength(pHead2);
        ListNode *p1 = pHead1, *p2 = pHead2;
        if(len1 > len2){
            while(len1 > len2){
                p1 = p1->next;
                --len1;
                }
            }
         if(len2 > len1){
             while(len2 > len1){
                 p2 = p2->next;
                 --len2;
                 }
             }
         while(p1){
             if(p1 == p2) return p1;
             p1 = p1->next;
             p2 = p2->next;
             }
        return p1;
    }

    int get_ListLength(ListNode* head){
        int len = 0;
        while(head){
            head = head->next;
            ++len;
            }
        return len;
    }
};

总结

链表题常用算法,双指针。两个链表之间的关系比较,考虑STL容器。

  • 31
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

澄澈i

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

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

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

打赏作者

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

抵扣说明:

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

余额充值