算法题之环形链表问题
环形链表问题1
思路1:利用快慢指针来实现
分析:
我们定义两个指针:分别指向头节点和头节点的下一个节点;
每一次慢指针平移一步(即平移到它的next节点),而快指针则平移两步(即平移到它的next的next节点),完成快指针追赶慢指针的操作;
如果该链表时环形链表,则一定会在某一个时间点,快指针会和慢指针在环内相遇
代码实现
/*
* 环形链表I:方法1:使用两个指针(快慢指针)来完成环形链表的是否有环判断问题
* 即定义一个指针first和指针second同时指向链表的头节点
* 将first指向下一个节点,second指向下下个节点,若second能赶上first,则表示存在环
* */
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
//即表示该链表不存在节点或者只存在一个节点
return false;
}
//定义两个指针slow和fast:进行追赶
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {//只要first不等于second,就一直进行追赶
if (fast == null || fast.next == null) {//若first为null或者first的下一个节点为null,说明不存在环形链表,则直接返回false
return false;
}
//将first指向它的下一个节点,second指向它的下下个节点
slow = slow.next;
fast = fast.next.next;
}
//退出while循环,说明second追赶上了first
return true;
}
思路2:使用HashSet存储的唯一性
分析:我们创建一个HashSet,遍历该链表:将节点加入HashSet中
如果存储的节点已经在HashSet中存在了,说明链表为环形的,则返回true;
如果遍历链表结束,没有返回true,则表示该链表不是环形的,则返回false;
代码实现
/*
* 环形链表I:方法2:使用HashSet的唯一性:将每一个节点的next域添加到HashSet中,若存在相同的next域,则说明存在环
* */
public boolean hasCycleByHash(ListNode head) {
if (head == null || head.next == null) {
//即表示该链表不存在节点或者只存在一个节点
return false;
}
HashSet<ListNode> set = new HashSet<>();
ListNode temp = head;
while (temp != null) {
if (!set.contains(temp)) {
set.add(temp);
temp = temp.next;
}else {
return true;
}
}
//说明遍历到链表尾部,仍未发现环,则返回false
return false;
}
环形链表问题2
问题分析
此时环形链表不仅需要判断是否为环形链表,而且还要返回环形链表的入口索引节点:
代码实现
//环形链表II:方法1:hashset法:
public ListNode detectCycle01(ListNode head) {
//如果头节点为空或者只有一个节点:则表示无环
if(head == null || head.next == null) {
return null;
}
//定义一个HashSet
HashSet<ListNode> set = new HashSet<>();
ListNode temp = head;
while (temp != null) {
if (set.contains(temp)) {
return temp;
}else {
set.add(temp);
temp = temp.next;
}
}
//while循环遍历结束,仍未发现环,则返回null
return null;
}
代码实现
//环形链表II:方法2:快慢指针法:快指针追赶上慢指针一定是在环的内部
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null;
}
//定义两个指针:slow和fast,以及一个存储最后返回的ListNode变量
ListNode slow = head;
ListNode fast = head;
ListNode temp = head;
while (true) {
if (fast == null || fast.next == null) {//当遍历到最后链表的最后一个节点:即无环,返回null
return null;
}
//将快指针指向next.next域,慢指针指向next域
fast = fast.next.next;
slow = slow.next;
//若快慢指针相遇了,则直接break返回,此时slow和fast指针指向的都是相遇时的位置
if (fast == slow) {
//当两者相遇了
break;
}
}
//将temp指针和fast指针一起同步移动,再次相遇则是环的起始位置
while (temp != fast) {
temp = temp.next;
fast = fast.next;
}
return temp;
}