leetcode 141. 环形链表

【前言】

           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:不完美的环状链表,即,链表中某一中间节点与尾部相连 
leetcode 141. 环形链表_第1张图片

一个环形链表(如图所示):{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;
    }
}

 

你可能感兴趣的:(Leetcode,Java,Test)