题目
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.
给定一个链表,判断一下链表中是否含有环。
样例输入输出
为了表示给定的链表中的环,我们用整数pos来代表链表中尾结点连接到的位置。如果pos值为-1,则代表链表中没有循环。
样例1:
输入:head = [3,2,0,-4],pos = 1
(表示一个含有3、2、0、-4四个结点的链表,且尾结点-4指向位置为1的结点2)
输出:true
(表示含有环)
样例2:
输入:head = [1,2],pos = 0
输出:true
样例3:
输入:head = [1],pos = -1
输出:false
思路
单链表中如果存在环,一定是尾部结点的next指针指向该链表中的其他结点,否则指向null。
所以我们需要记录每一结点是否已经被访问过。如果某结点第二次被访问,那么可以认为是尾节点指向了它,形成了闭环。
我们可以使用HashSet来储存值。
题解
/**
* 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) {
//储存所有被访问过的结点
HashSet nodesVisited = new HashSet();
while(head!=null){
if(nodesVisited.contains(head)){
return true;
}else{
nodesVisited.add(head);
head = head.next;
}
}
return false;
}
}
反思
复杂度分析
时间复杂度:O(n).
空间复杂度:O(n).
思路反思
- 最开始没有充分考虑单链表的特点,也没有很好地将模型抽象为程序语言,抽象能力有待提高。
- 习惯采用数组、链表等线性数据结构,而没有考虑到在当前题目这种需要频繁增加元素与查询元素的需求下,应该选取哈希表这种数据结构。看了别人的题解才有所意识。
扩展学习
在leetcode141给出的solution中,有一个approach(Two Pointers)很有意思,值得了解学习一下。
思路是这样的:
如果一个环形跑道上有两个速度不同的runner在奔跑,那么他们肯定会相遇。
同理,如果两个结点分别以1结点/次、2结点/次的速率在链表的环上(假设存在)移动,那么某一时刻他们一定代表同一结点。
以此来作为判断链表上是否存在环的依据。
代码如下:
/**
* 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 slow = head, fast = head.next;
while(slow!=fast){
//如果不存在环,那么肯定是fast结点先到达尾结点
if(fast == null || fast.next == null){
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
}
时间复杂度:O(n).
空间复杂度:O(1).