文章讲的两个力扣题
这两题主要讲思路,而不是代码,这题的代码过于简单,但是思路却异常的难,需要算法公式推导,这两题思路曾出现在大厂的面试题当中。
判断链表是否有环
这题是判断是否有环,这题巧就巧在,如果你不会其他题目,可以用暴力求解法解出来,但是这题是不行的,因为这题会造成死循环,所以没办法使用暴力求解法。
这题使用的是快慢指针的想法。但是要稳定求出快慢指针走几步,需要求解
1. slow走一步,fast走两步 一定能相遇吗?
因为fast比slow快,所以fast先进环,当slow进环时。fast开始追赶slow,只要fast能刚好遇到slow,我们就能判断链表是有环的。但也不排除他们可以会错开,永远追不上的情况。
这是slow进环时,fast大概的位置
我们先假设slow和fast的距离为N
那么fast开始追赶slow时,距离变化是 N-1...N-2...N-3...直到N=0。当N=0,就是他们相遇的地方,这样就能够判断链表一定有环。所以结论是 当slow走一步 fast走两步 fast一定能相遇
2.slow一次走一步,fast一次走三步 一定能相遇吗?
当slow进环时,假设slow和fast的距离为N,fast开始追赶slow 那么他们的距离变化是N-2...N-4...N-6;这里分两种情况
当N是偶数时
那么N-2,一直持续下去,N是一定会被减到0的,那么他们一定会相遇
当N是奇数时
那么N-2,只会被减到-1。这时候 我们有需要到另一个变量,就是环的长度,这里我们假设环的长度为C
他们的位置是不一定的,只是画个大概。fast一定是在slow的前一个位置,这时他们就错过了
他们的距离变为C-1
这里又分出了两种情况
假设C-1是偶数时
那么他们的距离又重新变成了偶数,那么fast追一圈后,再追就可以追得上
假设C-1时奇数时
那么他们的距离还是奇书,那么fast就永远会跟slow错过,fast永远不会与slow相遇
所以slow走一步,fast走三步,是有3种情况,所以是不一定能相遇
3.slow一次走1步,fast一次走四步,一定能相遇吗?
同上,当slow进环时,fast开始追赶slow,他们的距离是N,那么他们的距离变化是N-3...N-6...N-9...
当N是奇数时
N-3持续下去,N是会被减到0的,所以一定会追上
当N是偶数时
那么N会被减到-1或者-2,那么他们就错开了。
这里又分出了两种情况
当被减到-1时
他们的位置是fast比slow多一个位置,他们的距离变为C-1
当C-1是偶数时,他们就永远会错开,fast一定不会跟slow相遇
当C-1时奇数时,他们就会相遇
当被减到-2时
他们的位置时fast比slow多两个位置,他们的距离变为C-2
当C-2是偶数时,他们永远会错开,fast一定不会跟slow相遇
当C-2是偶数时,他们就会相遇
结论为 当slow一次走1步 fast一次走四步 共有6种情况 所以时不一定
接下来还有好多种情况,这里就步一一讲解,但是大概的思路时一样的。
当这个链表有环时,我们要挑选绝对能判断这个链表有环的情况,所以要选第一种,因为第一种时不受N和C的限制的,而2,3种情况都会受到影响。
那么这题就迎刃而解了。
环形链表源码
bool hasCycle(struct ListNode *head) {
struct ListNode* slow = head,*fast=head;
while(fast && fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
return true;
}
return false;
}
判断链表是否有环,并且返回入口点
这里有两种极端情况
当L比C大的很多时,当slow进环时,fast可能一圈都没走完
当L比C小很多时,当slow进环时,fast可能已经走很多圈了
但是slow进环时,fast开始追slow,fast只需要在一圈内就能跟slow相遇
根据前面的思路
我们就能推导出一个公式:
2*(L+N)=L+M*C+X
简化为
L+N=M*C
也相当于:
L=M*C-N
这里的M代表走了M圈的意思
那么代码就可以实现为,当他们有环时,我们假设他们的相遇点为meet,然后让meet和head(就是链表的头)开始一步一步走,当他们相遇时,他们就是链表的入环口
环形链表||源码
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow = head,*fast=head;
while(fast && fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
struct ListNode* meet=slow;
while(meet!=head)
{
meet=meet->next;
head=head->next;
}
return meet;
}
}
return NULL;
}
如果文章对您有帮助,希望能收获您的赞,感谢!