【前言】
python刷leetcode题解答目录索引:https://blog.csdn.net/weixin_40449300/article/details/89470836
github链接:https://github.com/Teingi/test
【正文】
141.环形链表
描述
给定一个链表,判断链表中是否有环。
进阶:
你能否不使用额外空间解决此题?
我…遍历了以后超出时间限制,于是看大家总结的方法。一个就是设置两个指针slow和fast,一个步长为1,一个步长为2进行遍历。如果有环,则slow和fast总会在某一点相遇。如果没有环,则fast会先为空,或者fast.next为空。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head is None or head.next is None or head.next.next is None:
return False
slow = head.next
fast = head.next.next
while slow != fast and fast is not None and fast.next is not None:
slow = slow.next
fast = fast.next.next
if fast == slow:
return True
else:
return False
通过了呢,但是我觉得我的代码不够优雅,还可以再进行简化。
关于环形链表的相关问题可以查看
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
fast = slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if slow == fast:
return True
return False
关于环形链表问题的总结(from Rotten_Pencil)
1.快慢指针一直到相遇时的循环次数等于环的长度。(可推导)
Case1:一个完美的环状链表,即链表头尾相连
一个环形链表:{A,B,C,A,B,C,……}
其上存在两个指针,A指针移动速度是B指针的两倍。
A,B同时从节点1出发,所经过的节点如下:
快指针A:A->C->B->A
慢指针B:A->B->C->A
A、B指针在节点A第一次相遇,循环次数为3,而环的程度正好也为3。那这个是不是巧合呢?
首先我们要理解的是循环的次数代表的是什么。
1. 每次循环,对于B这个慢指针来说,意味着走了一个单位长度。
2. 而对于A来说,走了两个单位长度。
3. 那么二者第一次相遇必然是在A走了2圈,B走了1圈的时候。
4. 假如A的速度是B的3倍,那么二者第一次相遇是在A走了3圈,B走了1圈的时候。
5. 同理A是B的5倍速度,相遇时A走了5圈,B走了1圈
…
n. A的速度是B的n倍,相遇时A走了n圈,B走了1圈
从上面的观察我们可以发现,无论A的速度是B的几倍,两者第一次相遇必然是在B走了1圈时。
因为B的速度代表的是链表基本的长度单位,即从一个节点移动到下一个节点的距离。
同时在链表中,每个节点与节点之间这个距离是不变的。
当循环结束时,B走了1圈,正好是环的长度。而B每次移动一个单位距离,因此环的长度等于循环次数。
Case2:不完美的环状链表,即,链表中某一中间节点与尾部相连
一个环形链表(如图所示):{D,E,A,B,C,A,B,C,……}
其上存在两个指针,A指针移动速度是B指针的两倍。
A,B同时从节点1出发,所经过的节点如下:
快指针A:D->A->C->B
慢指针B:D->E->A->B
根据上图,我们可以计算出A、B行走的距离:
A = d+e+a+b+c+a
B = d+e+a
因为A的速度是B的2倍,那么A行走的距离也因该是B的2倍:
d+e+a+b+c+a = 2(d+e+a)
a+b+c = d+e+a
从上图可以看出,a+b+c正好是环的长度,而d+e+a则是B行进的距离。
又知,每次循环B移动一个单位距离,因此在不完美的环状表中,循环次数亦是等于环的长度。
2.快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离。(可推导)
根据上文公式,我们可以继续推导,即:
a+b+c = d+e+a
b+c = d+e
b+c是相遇点到环入口的距离
d+e是链表起点到环入口的距离
相关问题:
- 判断是否为环形链表
思路:使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
- 若为环形链表,求环入口点
思路:快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离
- 求环的长度
思路:记录下相遇点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s
- 判断两个链表是不是相交(思路:如果两个链表相交,那么这两个链表的尾节点一定相同。直接判断尾节点是否相同即可。这里把这道题放在环形链表,因为环形链表可以拆成Y字的两个链表。)
142.环形链表 II
描述(虽然这是中等难度的题,不过我觉得有必要跟上一题放在一起。我可以考虑按类型来做题,不再按难度来做题了):
>
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
说明:不允许修改给定的链表。
进阶:
你是否可以不用额外空间解决此题?
我
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head is None or head.next is None:
return None
fast = head
slow = head
while fast.next and fast.next.next:
slow = slow.next
i+=1
fast = fast.next.next
if slow == fast:
p = head
while slow != p:
p = p.next
slow = slow.next
return p
return None
思路就是上面总结的:相遇点到环入口点的距离=头节点到环入口点的距离
java代码:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null)
return false;
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast)
return true;
}
return false;
}
}