用python 判断一个单链表是否有环

用python 判断一个单链表是否有环.

https://leetcode.com/problems/linked-list-cycle/

思路1:

判断一个单链表是否有环,
可以用 set 存放每一个 节点, 这样每次 访问后把节点丢到这个集合里面.
其实 可以遍历这个单链表, 访问过后,
如果这个节点 不在 set 里面, 把这个节点放入到 set 集合里面.
如果这个节点在 set 里面 , 说明曾经访问过, 所以这个链表有重新 走到了这个节点, 因此一定有环
如果链表都走完了, 把所有的节点都放完了. 还是没有重复的节点, 那说明没有环.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Time    : 2019/1/12 00:59
@File    : has_circle.py
@Author  : frank.chang@shoufuyou.com

https://leetcode.com/problems/linked-list-cycle/


141. Linked List Cycle
Easy

1231

93

Favorite

Share
Given a linked list, determine if it has a cycle in it.

To represent a cycle in the given linked list,
we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to.
If pos is -1, then there is no cycle in the linked list.



Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.


Example 2:

Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the first node.


Example 3:

Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.




Follow up:

Can you solve it using O(1) (i.e. constant) memory?

Accepted
340,579
Submissions
971,443

"""
class LinkNode:

    def __init__(self, value):
        self.value = value
        self.next = None


class Solution1:
    """
    思路分析:
    判断一个单链表是否有环,
    可以用 set 存放每一个 节点, 这样每次 访问后把节点丢到这个集合里面.
    其实 可以遍历这个单链表, 访问过后,
    如果这个节点 不在 set  里面, 把这个节点放入到 set 集合里面.
    如果这个节点在  set 里面 , 说明曾经访问过, 所以这个链表有重新 走到了这个节点, 因此一定有环.

    如果链表都走完了, 把所有的节点都放完了. 还是没有重复的节点, 那说明没有环.

    """

    def hasCycle(self, head):

        mapping = set()

        flag = False

        p = head

        while p:

            if p not in mapping:
                mapping.add(p)
            else:
                flag = True
                break
            p = p.next

        return flag

还有一个解决方案:

定义 两个指针, 一个快指针fast, 一个慢指针slow, 快指针一次走两步,慢指针一次走一步.
如果 两个指针相遇了, 则说明链表是有环的.
如果 fast 都走到null了, 还没有相遇则说明没有环.

为什么是这样呢? 简单分析一下?
图1

图片2

图片3

图片4
图片5

图片6

图片7
用图形来分析一下,这样可以清晰一点.

图形分析

因为快指针 先走 所以快指针先进入环,之后慢指针后进入环, 无论如何,

最后 要么 慢指针进入环的时候, 快指针可能已经走了 很多遍环, 也有可能没有走完环. 但无论如何 当慢指针 进入环的时候,
fast 有可能在 慢指针的后面, 或者前面, 无论如何 快指针 是必慢指针走的快的 , 所以 只要有环 一定可以 和慢指针来一次相遇.

你可能想 会不会错过呢?
答案 是不会的. 你想 快指针一次 走两步, 慢指针一次都一步.
假设 这是一条无穷尽的单链表. 他们 每走一步, 两者之间的距离就减1, 所以 只要链表足够长, 是一定会相遇的.

看下图:
图片8

class Solution:
    """
    定义 两个指针, 一个快指针fast, 一个慢指针slow,  快指针一次都两步,慢指针一次走一步. 
    如果 两个指针相遇了, 则说明链表是有环的. 
    如果 fast 都走到null了, 还没有相遇则说明没有环. 
    """

    def hasCycle(self, head):

        flag = False
        if head is None or head.next is None or head.next.next is None:
            return flag

        fast = head.next.next
        slow = head.next

        while fast is not slow:

            if fast.next is None or fast.next.next is None:
                # no circle
                return flag
            fast = fast.next.next
            slow = slow.next

        # 相遇肯定有环
        if fast is slow:
            # hasCircle
            flag = True

        return flag

第二次做DAY20201130

闲下来 之前的代码 写的不够优雅,今天 重新修改了一下 之前的代码,这样写看起来 比 之前的代码 稍微 好看一点,详细请看下面

141. 环形链表

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false

进阶:

你能用 O(1)(即,常量)内存解决此问题吗?

示例 1:

img

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

img

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

img

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos-1 或者链表中的一个 有效索引
方法1 路径记录法
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        visited = set() 
        while head:
            cur = head
            if cur not in visited:
                visited.add(cur)
            else:
                return True
            head = head.next 
        return False 

 
class Solution02:
    def hasCycle(self, head: ListNode) -> bool:
        seen = set()
        while head:
            if head in seen:
                return True
            seen.add(head)
            head = head.next
        return False

方法2 快慢指针法
第1种解法
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if not head:
            return False 

        slow = head 
        fast = head.next 

        while fast and fast.next:
            if fast ==slow:
                return True 
            fast= fast.next.next 
            slow = slow.next 
            
        return False 
另一种写法
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if head is None or  head.next is None:
            return False 
        
        slow = head 
        fast  =head.next 
        while slow != fast:    
            if fast is None or fast.next is None:
                return False 
            fast = fast.next.next 
            slow = slow.next 

        return True 
分享感动,留住快乐. 2019-01-27 11:53:45 --frank
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值