成君:秒懂单链表寻找环入口、计算环头结点到环入口距离
单链表寻找环入口问题
一、构造链表
public class ListNode {
int val;
ListNode next;
}
二、3个步骤
1. 判断是否存在环:快慢指针法
/**
* 判断是否有环
* @return ListNode 相遇结点
*/
public ListNode hasLoop(ListNode pHead) {
if (pHead == null || pHead.next == null || pHead.next.next == null) {
return null;
}
ListNode slow = pHead.next;// 慢指针 1 步
ListNode fast = pHead.next.next;// 快指针
while(fast != null) {
if(slow.equals(fast)) {
return slow;
}
slow = slow.next;// 慢指针
fast = fast.next;
if(fast != null) {
fast = fast.next;// 快指针 2 步
}
}
return null;
}
2. 获取环的长度
/**
* 获取环的长度
*/
public int getLoopLength(ListNode node) {
if (node == null) {return 0;}
ListNode temp = node.next;
int length = 1;
while(temp != node) {
length++;
temp = temp.next;
}
return length;
}
3. 获取环入口:假设无环,双指针法获取倒数第 length 个结点
/**
* 获取入口结点
*/
public ListNode getEntryNode(ListNode pHead, int length) {
if (length == 0) {return null;}
ListNode a = pHead;
ListNode b = pHead;
while (length-- > 0) {
a = a.next;
}
while (a != b) { // 相遇时便是链尾,即入口
a = a.next;
b = b.next;
}
return a;
}
测试
public void test(ListNode pHead) {
ListNode node = getEntryNode(getLoopLength(hasLoop(pHead)));
}
三、总结
双指针可以解决大部分链表问题