题目描述
给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
数据范围: n≤10000,1<=结点值<=10000
要求:空间复杂度 O(1),时间复杂度 O(n)
例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:
可以看到环的入口结点的结点值为3,所以返回结点值为3的结点。
输入描述:
输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台会根据第二段是否为空将这两段组装成一个无环或者有环单链表
返回值描述:
返回链表的环的入口结点即可,我们后台程序会打印这个结点对应的结点值;若没有,则返回对应编程语言的空结点即可。
例1
输入:
{1,2},{3,4,5}
返回值:
3
说明:
返回环形链表入口结点,我们后台程序会打印该环形链表入口结点对应的结点值,即3
例2
输入:
{1},{}
返回值:
"null"
说明:
没有环,返回对应编程语言的空结点,后台程序会打印"null"
例3
输入:
{},{2}
返回值:
2
说明:
环的部分只有一个结点,所以返回该环形链表入口结点,后台程序打印该结点对应的结点值,即2
思路
双指针:快慢指针
通过定义slow和fast指针,slow每走一步,fast走两步,若是有环,则一定会在环的某个结点处相遇(slow == fast),根据下图分析计算,可知从相遇处到入口结点的距离与头结点与入口结点的距离相同。
具体实现
#include <iostream>
#include <malloc.h>
#include <string>
using namespace std;
typedef struct Lnode
{
int key;
Lnode* next;
}linknode,*linklist;
linklist creatcircle()//创造一个有环路的链表
{
linklist l = (linklist)malloc(sizeof(linknode));
l->key = NULL;
l->next = NULL;
linknode* p = l, * q = p,*r;
cout << "请输入链表非环部分:" << '\n' << endl;
string str1, str2;
char ch;
while((ch = getchar()) != '\n')//构造链表的前半部分
{
if (ch > 47 && ch < 58)
{
q = (linklist)malloc(sizeof(linknode));
q->key = (ch - 48);
q->next = NULL;
p->next = q;
p = p->next;
}
}
r = p;
cout << "请输入环的部分:" << '\n' << endl;
while ((ch = getchar()) != '\n')//构造链表的环路部分
{
if (ch > 47 && ch < 58)
{
q = (linklist)malloc(sizeof(linknode));
q->key = (ch - 48);
q->next = NULL;
p->next = q;
p = p->next;
}
}
p->next = r->next;//连接成环
return l;
}
int solution(linklist l)
{
linknode* fast = l, * slow = fast;//用快慢指针来找环路
while (fast)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)//快慢指针相遇在环的入口处
{
return fast->key;
}
}
cout << "不存在环路" << '\n' << endl;
return NULL;
}
int main()
{
linklist l = creatcircle();
cout << solution(l) << endl;
return 0;
}
时间复杂度:On
空间复杂度:On
小结:
始终要注意输入数字时字符型和整形的转化
求环长:fast走2x时遇到走x步的slow,环长x