栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

LeetCode 142

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

LeetCode 142

本人转码小白,正在学习算法,欢迎各位大佬批评指正。算法思想来自博客代码随想录。


1.题目描述:

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

2.题解思路:
  •  首先判断是否有环
  •  如果有环,找到环起点

2.1 使用快慢指针法判断是否有环

令slow指针和fast指针指向头结点,slow每次走一步,fast每次走两步,如果存在环的话,fast和slow会在环内相遇。

(为什么会相遇?因为对于slow来说,fast是一步一步的靠近slow。我们假设slow不动,只有fast在环内每次走一步,肯定会和slow相遇)

(为什么在环内?因为fast进入环内,就不会出来了)

2.2 公式推一下,找环起点

头结点到环起点的结点数为x ,环起点到相遇点结点数为y,相遇点再到起点结点数为z。

相遇时,slow走过的结点数为(x+y)(后文解释),fast走过的结点数为x+n(y+z)+y。

fast走过的结点数时slow的两倍,所以2*(x+y) = x+n(y+z)+y,变一下形式啦。

x+y = n(y+z)

x = n(y+z) -y

x = (n-1)(y+z) +z

n为圈数,一定是>=1的。当n=1时,x = z,这意味着从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环起点。当n>1时,其实就是fast多转了几圈,结果同理。

为什么相遇时slow走过的结点数为(x+y)?

假如slow和fast都在环起点时, slow转一圈,fast转两圈,结果刚好在入环口相遇。也就意味着最坏的相遇是在入环口,此时走的路最多(slow走了整整一圈)。

然而,当slow在环起点,fast一定是在环的任意位置,所以必定会在slow的第一圈内一点相遇。

举个例子:

下面列举了起始时刻,slow和fast都在1;slow在1fast在2;slow在1fast在3;slow在1fast在4时的4种相遇情况。

3.本地实现
  1. 先创一个环形链表 3->2->0->-4   -4指向2 形成环
    ListNode* creatList()
    {
    	ListNode* head = NULL;
    	ListNode* cur = NULL;
    	ListNode* temp = NULL;
    	vector nums = { 3,2,0,-4 };
    	for (int i = 0; i < nums.size(); i++)
    	{
    		if (head == NULL)
    		{
    			head = new ListNode(nums[i]);
    			cur = head;
    		}
    		else
    		{
    			cur->next = new ListNode(nums[i]);
    			if (nums[i] == 0)
    			{
    			    temp = cur->next; //存一下2,最后把-4指向2
    			}
    			cur = cur->next;
    		}
    		cur->next = temp;
    	}
    	return head;
    }

    因为是环,输出一下前10位看看结果。

完整代码

#include
#include
using namespace std;

struct ListNode
{
	int val;
	ListNode* next;
	ListNode(int x) :val(x), next(NULL) {}
};

//先创一个环形链表 3->2->0->-4   -4指向2 形成环
ListNode* creatList()
{
	ListNode* head = NULL;
	ListNode* cur = NULL;
	ListNode* temp = NULL;
	vector nums = { 3,2,0,-4 };
	for (int i = 0; i < nums.size(); i++)
	{
		if (head == NULL)
		{
			head = new ListNode(nums[i]);
			cur = head;
		}
		else
		{
			cur->next = new ListNode(nums[i]);
			if (nums[i] == 0)
			{
			    temp = cur->next; //存一下2,最后把-4指向2
			}
			cur = cur->next;
		}
		cur->next = temp;
	}
	return head;
}

class Solution 
{
public:
	ListNode* detectCycle(ListNode* head)
	{
		ListNode* fast = head;
		ListNode* slow = head;
		//开始走
		while (fast != NULL && slow != NULL)//有环的话相当于while(1),没环的话fast肯定会走到空值,返回NULL即可。
		{
			slow = slow->next;//slow走一步
			fast = fast->next->next;//fast走两步
			if (slow == fast)//遇上了,说明有环,开始找环起点。
			{
				ListNode* index1 = fast;//指针1 从相遇点开始走
				ListNode* index2 = head;//指针2 从头结点开始走
				//两者相遇的位置即为环起点
				while (index1 != index2)
				{
					index1 = index1->next;
					index2 = index2->next;
				}
				return index1;//环起点
			}
		}
		return NULL;
	}
};



int main()
{
	Solution solution;
	ListNode* test = creatList();
	ListNode* ans = solution.detectCycle(test);
	cout << ans->val << endl;//题目要求输出指针即可,这里输出值方便检查结果
	system("pause");
	return 0;
}

消化后加了些自己的理解,不算纯纯搬运工吧,就当作自己的学习笔记。

码字不易,小白求带。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/846915.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号