判断链表是否有环、求环长度
如 A->B->C->D->E->B
方法1:判断两个指针走到某点步数是否一致
如指针1走到第二个B时用了5步,而从头遍历的指针2走到B时只用了2步,说明有环。
环长度 = step2 - step1
平均时间复杂度O(n²),平均空间复杂度O(1)
public static boolean circle() {
// 两个指针指向头
Node p1 = head, p2 = head;
// 双循环遍历节点
for (int step1 = 0; p1 != null; step1++) {
p1 = p1.next;
for (int step2 = 0; p2 != p1; step2++) {
p2 = p2.next;
}
// 步数不一致,说明有环
if (step2 != step1) {
return true;
}
p2 = head;
}
return false;
}
方法2:Set去重
利用set的去重特性,HashSet入堆时 put(element) 方法会自判断是否已存在,若已存在,会返回false。
环长度自定义feild累加即可。
平均时间复杂度为O(n),空间复杂度为O(n)。
方法3:快慢指针
快指针每次走2步,慢指针每次走1步。如果有环,慢指针必定会与快指针相遇。
环长度:相遇两次,第二次相遇时快指针走了2s步,慢指针走了1s步,环长度即为 2s - 1s =1s
平均时间复杂度为O(n),空间复杂度为O(1)
public static boolean circle3() {
// 从头开始
Node slow = head, fast = head;
// 有终止节点,说明无环
while (fast != null && fast.next != null) {
// 分别前进1步、2步
slow = slow.next;
fast = fast.next.next;
// 慢指针追上快指针
if (slow == fast) {
return true;
}
}
return false;
}