《剑指offer》:[37]如何得到链表环的入口地址

题目:如何得到链表环的入口结点

方案:分两步走:

第一步:先要找到链表中的环,得到环的结点的个数。可以设置两个指针一个走的比较快,一个比较慢,那么如果链表中存在一个环,那么这两个指针一定会陷入这个环中,快的指针一定会遇到慢的指针,所以很快就能遇到。因为前面有详细讲过,这里不再多介绍,给一张图吧。

第二步:得到环的个数以后,我们照样可以设置两个指针。第一个指针先前进N(N为环中结点的个数)步,然后和第二个指针以相同的速度前进,当它们相遇时的结点就是链表中环的入口。

具体过程如下图所示:

具体实现代码如下所示:

#include <iostream>
using namespace std;
struct  List
{
	int data;
	List *next;
};
int arr[7]={1,2,3,4,5,6,7};
List *pHead=NULL;
List *pNext=NULL;
List *pEnd=NULL;
bool InputInvalid=false;
void Listhelp(List **head,int data)
{
	List *temp=new List ;
	temp->data=data;
	temp->next=NULL;
	if(NULL==*head)
	{
		*head=temp;
		pEnd=temp;
	}
	else
	{
		pEnd->next=temp;
		pEnd=temp;
	}
}
void CreateList(List **head,int *array,int length)
{
	for(int i=0;i<length;i++)
		Listhelp(head,array[i]);
	//制造一个环;7->4
	List *temp=*head;
	while(temp->data!=4)
		temp=temp->next;
	pEnd->next=temp;
}
void show(List *head)
{
	int count=0;
	while(head)
	{
		cout<<head->data<<" ";
		head=head->next;
		count++;
		if(count==15)
			break;//有环所以用break退出;
	}
}
int GetNumOfCircle(List *head)
{
	int NodeCount=1;
	if(NULL==head)
	{
		InputInvalid=true;
		return 0;
	}
	List *pSlow=head->next;
	if(pSlow==NULL)
	{
		InputInvalid=true;
		return 0;
	}
	List *pFast=pSlow->next;// two steps;
	while(pSlow!=NULL && pFast!=NULL)
	{
		if(pFast==pSlow)
			break; //找到环;
		pSlow=pSlow->next;
		pFast=pFast->next;
		if(pFast!=NULL)
			pFast=pFast->next;
	}
	//计算环的个数;
	while(pFast->next!=pSlow)
	{
		pFast=pFast->next;
		NodeCount++;
	}
	return NodeCount;
}
//得到环的入口地址;
List *EntryNodeOfLoop(List *head,int count)
{
	List *pNode1=head;
	for(int i=0;i<count;i++)
		pNode1=pNode1->next;
	List *pNode2=head;
	while(pNode1!=pNode2)
	{
		pNode1=pNode1->next;
		pNode2=pNode2->next;
	}
	return pNode1;
}
int main()
{
	int NodeCircle=0;
	List *EnterNode=NULL;
	CreateList(&pHead,arr,7);
	cout<<"有环4567:";
	show(pHead);
	cout<<endl;
	NodeCircle=GetNumOfCircle(pHead);
	if(InputInvalid)
		cout<<"THE INPUT IS [email protected]!"<<endl;
	else
	{
		EnterNode=EntryNodeOfLoop(pHead,NodeCircle);
		cout<<"环入口结点的值为:"<<EnterNode->data<<endl;
	}
	system("pause");
	return 0;
}

运行结果如下:

时间: 2024-11-05 14:53:21

《剑指offer》:[37]如何得到链表环的入口地址的相关文章

剑指offer (37) 两个链表的第一个公共结点

题目:输入两个链表,找出它们的第一个公共结点 如果两个链表有公共结点,那么公共结点一定出现在两个链表的尾部 如果两链表长度不相等,那么达到公共结点的步数就不一致,如何确保 两个链表从头开始遍历,同步达到公共结点? 这是关键所在 如果两链表长度相同,那么就可以同步达到了? 由此,我们就需要 让两个链表长度"相等" 我们假设 两链表长度分别为m和n,且m > n, 那么我们可以在较长链表中 先走 m - n 步,然后 两个链表游标同步走,如果有公共结点,那么就一定同时达到 ListN

【剑指offer】两个链表的第一个公共结点

转载请注明出处:http://blog.csdn.net/ns_code/article/details/26097395 简单题,剑指offer上的第37题,九度OJ上AC. 题目描述: 输入两个链表,找出它们的第一个公共结点. 输入: 输入可能包含多个测试样例.对于每个测试案例,输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的两个链表的元素的个数.接下来的两行,第一行为第一个链表的所有元素,中间用空格隔开.第二行为第二个链表的所有元素,中间用空格隔开. 输出: 对应

剑指OFFER之合并有序链表(九度OJ1519)

题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则.(hint: 请务必使用链表.) 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行为两个整数n和m(0<=n<=1000, 0<=m<=1000):n代表将要输入的第一个链表的元素的个数,m代表将要输入的第二个链表的元素的个数.下面一行包括n个数t(1<=t<=1000000):代表链表一中的元素.接下来一行包含m个元素,s(1<

剑指offer之【复杂链表的复制】

题目: 复杂链表的复制 链接: https://www.nowcoder.com/practice/f836b2c43afc4b35ad6adc41ec941dba?tpId=13&tqId=11178&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 题目描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为

【Java】 剑指offer(37) 序列化二叉树

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 请实现两个函数,分别用来序列化和反序列化二叉树. 思路 一般情况下,需要采用前/后序遍历和中序遍历才能确定一个二叉树,但是其实可以只采用前序遍历(从根结点开始),将空结点(null)输出为一个特殊符号(如“$”),就可以确定一个二叉树了. 将二叉树序列化为字符串,就是前序遍历的过程,遇见空结点时,序列化为“$”,每个结点间使用逗号分隔开. 将字符串反序列化为二叉树,也使用前

【剑指offer】18.删除链表中重复节点

思路 实现 /* 说下大概思路: 与链表的其他题目类似,为了防止删除头结点的极端情况发生,先创建空结点dummy,使dummy指向传入的head结点. 然后创建cur的指针,指向链表的头部(即dummy). 接着对cur指针迭代,因为要对比cur(cur最初始的定义指向空结点)指针的下一个结点与下下一个结点的值是否相等,为了防止产生空指针异常,故退出迭代的条件为:cur.next != null && cur.next.next != null. 在迭代过程中,如果cur.next.val

剑指offer系列62---两个链表的公共结点

[题目]输入两个链表,找出它们的第一个公共结点. * [思路]1 获取两链表的长度: * 2 让长的链表先走n步后此时走到短链表起始位置: * 3 两链表同时遍历,直至相同,这时返回第一个公共结点. 1 package com.exe11.offer; 2 3 /** 4 * [题目]输入两个链表,找出它们的第一个公共结点. 5 * [思路]1 获取两链表的长度: 6 * 2 让长的链表先走n步后此时走到短链表起始位置: 7 * 3 两链表同时遍历,直至相同,这时返回第一个公共结点. 8 * @

剑指offer系列13---反转链表并输出头结点

[题目]输入一个链表,反转链表后,输出链表的所有元素. [思路]将当前指针指向前者即为反转,反转是同时反转指针和赋值操作.即将指针指向前者并给前者赋值.反转后的头结点就是原链表的尾 结点.代码如下: 1 package com.exe3.offer; 2 /** 3 * 13[题目]输入一个链表,反转链表后,输出链表的所有元素. 4 * @author WGS 5 * 6 */ 7 public class ReverseLinkList { 8 public static class Link

剑指offer 56.删除有序链表中的重复结点

56. 删除有序链表中的重复结点 题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 分析 借助辅助头结点,可避免单独讨论头结点的情况.设置两个结点 pre 和 cur,当 cur 和 cur.next 值相等,cur 一直向前走,直到不等退出循环,这时候 cur 指的值还是重复值,调整 cur 和 pre 的指针再次判断 /*