返回
算法成长之路一:环形链表的征服之路
前端
2023-12-31 07:06:57
**引言**
欢迎来到我的算法成长之路!在这个系列文章中,我将分享我在刷题过程中的心得体会、算法思路和代码实现。每一篇都会聚焦一个特定的算法或数据结构,旨在帮助大家循序渐进地提升算法能力。
**初识环形链表**
环形链表是一种特殊类型的链表,其中最后一个结点的next域指向链表中的某个已存在结点,形成一个闭合的环路。与普通链表不同,环形链表没有显式的表尾结点。
**LeetCode 141:环形链表**
LeetCode 141题要求判断一个给定的链表是否包含环路。以下是这道题的题目
给定一个链表,判断链表中是否有环。
为了表示给定的链表,我们使用整数数组 A。每个元素 A[i] 代表链表中的第 i 个结点的值。如果链表中有环,则 A[i] 的值可以重复出现。链表中的所有结点都保证是 0 <= A[i] <= 1000。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个结点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个结点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
**算法思路**
为了判断一个链表中是否存在环路,我们可以使用两种常见的算法:
**1. 双指针法**
这种方法使用两个指针,一个称为快指针,另一个称为慢指针。快指针每次前进两步,而慢指针每次前进一步。如果链表中有环,快指针最终会追上慢指针,表明存在环路。
**2. 哈希表法**
这种方法使用一个哈希表来存储已访问过的结点。当遍历链表时,如果遇到一个已经存在于哈希表中的结点,则说明存在环路。
**代码实现**
以下是用Python实现的双指针法的代码:
```python
def has_cycle(head):
"""
判断链表中是否存在环路。
参数:
head: 链表的头结点。
返回:
如果存在环路,返回True;否则,返回False。
"""
# 定义快慢指针。
fast = head
slow = head
# 遍历链表。
while fast and fast.next:
# 快指针前进两步。
fast = fast.next.next
# 慢指针前进一步。
slow = slow.next
# 如果快慢指针相遇,说明存在环路。
if fast == slow:
return True
# 如果快指针到达链表末尾,说明不存在环路。
return False
代码优化
双指针法的时间复杂度为O(n),其中n为链表的长度。为了进一步优化性能,我们可以使用弗洛伊德循环检测算法 。该算法的思想是:如果链表中有环,那么快慢指针最终会在环内相遇。相遇点到环入口点的距离等于环的长度。因此,我们可以使用快慢指针再次遍历链表,并计算快慢指针相遇点到链表头结点的距离。如果该距离等于环的长度,则说明存在环路。
弗洛伊德循环检测算法 的代码实现如下:
def has_cycle(head):
"""
判断链表中是否存在环路。
参数:
head: 链表的头结点。
返回:
如果存在环路,返回True;否则,返回False。
"""
# 定义快慢指针。
fast = head
slow = head
# 遍历链表,直到快慢指针相遇。
while fast and fast.next:
# 快指针前进两步。
fast = fast.next.next
# 慢指针前进一步。
slow = slow.next
# 如果快慢指针相遇,说明存在环路。
if fast == slow:
break
# 如果快慢指针未相遇,说明不存在环路。
if not fast or not fast.next:
return False
# 计算快慢指针相遇点到链表头结点的距离。
distance = 0
temp = head
while temp != slow:
temp = temp.next
distance += 1
# 计算环的长度。
length = 0
temp = slow.next
while temp != slow:
temp = temp.next
length += 1
# 如果相遇点到头结点的距离等于环的长度,说明存在环路。
return distance == length
结语
通过本文,我们深入探讨了环形链表及其循环检测算法。双指针法和弗洛伊德循环检测算法都是高效且实用的方法。通过对这些算法的理解和实践,我们可以不断提升我们的算法能力,为解决更复杂的算法问题做好准备。