「这是我参与11月更文挑战的第 7 天,活动详情查看:2021最后一次更文挑战」
刷算法题,从来不是为了记题,而是练习把实际的问题抽象成具体的数据结构或算法模型,然后利用对应的数据结构或算法模型来进行解题。个人觉得,带着这种思维刷题,不仅能解决面试问题,也能更多的学会在日常工作中思考,如何将实际的场景抽象成相应的算法模型,从而提高代码的质量和性能
判断链表是否有环
题目来源:牛客网-NC4 判断链表中是否有环
题目描述
判断给定的链表中是否有环。如果有环则返回true,否则返回false
数据范围:链表长度 0 ≤ n ≤ 100000,链表中任意节点的值满足 |val| <= 100000
要求:空间复杂度 O(1),时间复杂度 O(n)
输入分为2部分,第一部分为链表,第二部分代表是否有环,然后回组成head头结点传入到函数里面。-1代表无环,其他的数字代表有环,这些参数解释仅仅是为了方便读者自测调试。实际在编码时读入的是链表的头节点
例如输入{3,2,0,-4},1时,对应的链表结构如下图所示:
可以看出环的入口结点为从头结点开始的第1个结点,所以输出true
示例
示例 1
输入:{3,2,0,-4},1
返回值:true
说明:第一部分{3,2,0,-4}代表一个链表,第二部分的1表示,-4到位置1,即-4->2存在一个链接,组成传入的head为一个带环的链表 ,返回true
示例 2
输入:{1},-1
返回值:false
说明:第一部分{1}代表一个链表,-1代表无环,组成传入head为一个无环的单链表,返回false
示例 3
输入:{-1,-7,7,-4,19,6,-9,-5,-2,-5},6
返回值:true
解题
思路
假设链表中有环,会是什么情况?就是无论怎样遍历都不会遍历到next等于空的情况。如何才能知道它是一直在循环遍历?有个暴力的方法就是,我遍历到每一个结点的时候,都去判断一下,它的next,有没有指向我前边已经遍历过的结点。但是这中方式,复杂度比较高
你假设有两个人在操场上跑步,一个人速度快,一个人速度慢(他俩的速度假设都不变),会出现什么情况?总有某一个时刻,他们会相遇。那把这种情况用在环的判断上,假设有两个指针,他们都遍历链表,但是步长不一样(每次遍历结点的个数),如果链表有环的话,他们一定会在某一个点相遇
比较好理解,这里就不画图了
代码
func hasCycle(head *LinkList.Node) bool {
if head == nil || head.Next == nil {
return false
}
if head.Next == head {
return true
}
slow, fast := head, head
for fast.Next != nil {
fast = fast.Next.Next
slow = slow.Next
if fast == nil {
return false
}
if fast == slow {
return true
}
}
return false
}