题目链接地址:
题目描述:
输入两个链表,找出它们的第一个公共结点。
输入:
输入可能包含多个测试样例。
对于每个测试案例,输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的两个链表的元素的个数。
接下来的两行,第一行为第一个链表的所有元素,中间用空格隔开。第二行为第二个链表的所有元素,中间用空格隔开。
输出:
对应每个测试案例,
输出两个链表的第一个公共结点的值。
如果两个链表没有公共结点,则输出“My God”。
样例输入:
5 4
1 2 3 6 7
4 5 6 7
3 3
1 5 7
2 4 7
2 3
1 3
4 5 6
样例输出:
6
7
My God
解题思路:
根据题意,在这道题中两个链表的公共结点应该是指两个链表中结点值相等的结点,而不是内存地址相同的结点。《编程之美》中有一道判断两个链表是否相交的题目,后面的扩展题中就有求出两个链表相交的第一个结点。如果两个链表相交,那么它们就会构成一个Y型结构,如图1所示:
图1 两个链表相交的情形
从图1可以看出,两个相交的链表,它们的尾部会出现一段共享的结点序列。所以我的想法是从两个链表的尾结点开始,依次向前查找共享的结点序列即可找到第一个公共结点,但是这种算法WA了。。。
后来看了一下作者的博客 程序员面试题精选100题(35)-两链表的第一个公共结点[数据结构]
作者的算法是先将两个链表按照尾部对齐,然后再从头到尾依次进行比较找出第一个公共结点。我是采用这种算法AC的。
举个栗子,对于测试用例
5 4
1 2 3 6 7
4 5 6 7
因为链表1的长度是5,链表2的长度是4,
所以先单独遍历链表1的第一个结点’1’,这样就将这两个链表“对齐”了;
然后再同时遍历链表1的第二个结点’2’和链表2的第一个结点’4’;
然后再同时遍历链表1的第三个结点’3’和链表2的第二个结点’5’;
然后再同时遍历链表1的第四个结点’6’和链表2的第三个结点’6’,
因为这两个结点值相等,所以可以得知结点’6’是两个链表的第一个公共结点。
AC代码如下:
#include<stdio.h>
#include<malloc.h>
#include<stack>
using namespace std;
// 定义单链表结点的结构
typedef struct Node
{
int data;
Node * next;
}Linklist;
/**
* 创建单链表
* @param n 单链表的结点数目
* @return head 返回链表的头指针
*/
Linklist * createLinklist(int n)
{
Linklist * head = (Linklist *)malloc(sizeof(Linklist));
head -> next = NULL;
Linklist * p = head; // p指针始终指向链表的最后一个结点
Linklist * s; // s指针指向新构造的链表结点
int i;
int data;
for(i = 1;i <= n;i++)
{
scanf("%d",&data);
s = (Linklist *)malloc(sizeof(Linklist));
s -> data = data;
s -> next = p -> next;
p -> next = s; // 将s插入到p结点的后面
p = s; // p指针指向当前链表的最后一个结点
}
return head;
}
/**
* 将两个链表按照尾部对齐,然后再从头到尾依次进行比较找出第一个公共结点
* @param linkhead1 链表1的头指针
* @param linkhead2 链表2的头指针
* @param m 链表1的结点个数
* @param n 链表2的结点个数
* @param commonNode 用于存放两个链表的公共结点
* @return bool 如果两个链表有公共结点,则返回true,否则返回false
*/
bool findCommonNode(Linklist * linkhead1,Linklist * linkhead2,int m,int n,int & commonNode)
{
bool isFind = false;
int gapLength; // 两个链表之间的长度差
// 对齐两个链表
if(m > n)
{
gapLength = m - n;
while(gapLength--)
{
linkhead1 = linkhead1 -> next;
}
}
else
{
gapLength = n - m;
while(gapLength--)
{
linkhead2 = linkhead2 -> next;
}
}
while(linkhead1 != NULL && linkhead2 != NULL)
{
if(linkhead1 -> data == linkhead2 -> data)
{
isFind = true;
commonNode = linkhead1 -> data;
break;
}
else
{
linkhead1 = linkhead1 -> next;
linkhead2 = linkhead2 -> next;
}
}
return isFind;
}
int main()
{
bool isFind;
int m,n;
int commonNode;
Linklist * linkhead1;
Linklist * linkhead2;
while(EOF != scanf("%d%d",&m,&n))
{
linkhead1 = createLinklist(m);
linkhead2 = createLinklist(n);
isFind = findCommonNode(linkhead1->next,linkhead2->next,m,n,commonNode); // 传入两个链表的首元结点和各自的长度
if(true == isFind)
printf("%d\n",commonNode);
else
printf("My God\n");
}
return 0;
}
/**************************************************************
Problem: 1505
User: blueshell
Language: C++
Result: Accepted
Time:70 ms
Memory:3924 kb
****************************************************************/