问题一:
如何判断一个单链表是否有环,如果有,则返回第一个进入环的节点,没有则返回null。
思路:
快慢指针
(1)定义快指针fast,满指针slow,开始时候,fast和slow都指向链表的头节点,slow每次走一步,fast每次走两步。
(2)如果fast到了终点,说明无环,返回null。
(3)如果有环,fast和slow一定会在某个位置相遇,此时让fast指针重新回到头节点,然后fast和slow同时一步一步移动,再次相遇的点就是入环节点。
代码实现:
public Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node slow = head.next;
Node fast = head.next.next;
while (slow != fast) {
//如果走到空 说明无环,直接返回null
if (fast.next == null || fast.next.next == null) {
return null;
}
//慢指针走一步 快指针走两步
slow = slow.next;
fast = fast.next.next;
}
//此时slow和fast相遇,让fast回到头节点
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
问题二:
如何判断两个无环链表是否相交,相交则返回第一个相交节点,不相交则返回null。
思路:
(1)链表1从头节点开始走到最后一个节点,统计链表1的长度为len1,记录最后一个节点end1。
(2)链表2从头节点开始走到最后一个节点,统计链表2的长度为len2,记录最后一个节点end2。
(3)如果 end1 != end2,则说明两个链表不相交,返回null,如果end1 == end2,说明两个链表相交。
(4)如果链表1较长,链表1就先走len1-len2步,同理链表2较长,链表2就先走len2-len1步。然后一起走,两个链表第一次走到的节点就是相交节点。
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
while (cur1.next != null) {
n++;
cur1 = cur1.next;
}
while (cur2.next != null) {
n--;
cur2.next = cur2;
}
//判断此时cur1和cur2是否相等
if (cur1 != cur2) {
return null;
}
//n大于0说明链表1更长 只要记住 cur1永远是指的更长的链表的头节点
//n>0时,cur1是head1 cur2是head2
//n<0时,cur1是head2 cur2是head1
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n); //取绝对值
//更长的链表先把多出来的长度走完
while (n != 0) {
n--;
cur1 = cur1.next;
}
//走完之后一起走
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}