两个单链表相交的一些问题
描述:在本题中,单链表可能有环,也可能无环。给定两个单链表的头节点head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null即可。
要求:如果链表1的长度为N,链表2的长度为M,时间复杂度请达到O(N+M),额外空间复杂度请达到O(1).
public class GetIntersectNode {
/*描述:在本题中,单链表可能有环,也可能无环。
* 给定两个单链表的头节点head1和head2,这两个链表可能相交,也可能不相交。
* 请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null即可。
**要求:如果链表1的长度为N,链表2的长度为M,时间复杂度请达到O(N+M),额外空间复杂度请达到O(1)。
*/
public static void main(String[] args) {
//测试用例
}
public static Node getIntersectNode(Node head1,Node head2) {
if(head1 == null || head2 == null) {
return null;
}
//1.首先需要先判断两个链表中是否有环,调用方法返回入环节点;如果链表无环,则返回null
Node node1LoopNode = getLoopNode(head1);
Node node2LoopNode = getLoopNode(head2);
//2.此时需要分类讨论,分为两个都有环,一个有环一个无环,两个都无环,三种情况
//3.两个都无环,先判断两个链表的尾节点是否相同,并记录链表长度。
//不相同则不相交,相同则相交;再让长链表指针先走,后两个指针一起走,相交的节点即可找到。
if(node1LoopNode == null && node2LoopNode == null) {
return noLoop(head1, head2);
}
//4.两个链表都有环
if(node1LoopNode != null && node2LoopNode != null) {
return bothLoop(head1,node1LoopNode, head2,node2LoopNode);
}
//5.一个有环,一个无环,不可能相交
return null;
}
/*思路:一个快指针,一次走两步,一个慢指针一次走一步,
当快指针走到null时则说明链表无环;若两个指针相遇,
则说明该链表有环。
此时再创建一个慢指针从头节点和当前慢指针同时出发,两个
慢指针相遇的地方即为入环节点。
*/
//获得入环节点,若无环则返回null
public static Node getLoopNode(Node head) {
if(head.next == null || head.next.next != null) {
return null;
}
Node slow = head.next;
Node fast = head.next.next;
while(fast.next != null && fast.next.next != null) {
if(fast == slow) {
fast = head;
while(fast != slow) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
fast = fast.next.next;
slow = slow.next;
}
return null;
}
//两个链表都无环,返回相交节点
public static Node noLoop(Node head1, Node head2) {
int len1 = 1;
int len2 = 1;
Node cur1 = head1;
Node cur2 = head2;
while(cur1.next != null) {
len1++;
cur1 = cur1.next;
}
while(cur2.next != null) {
len2++;
cur2 = cur2.next;
}
if(cur1 != cur2) {
return null;
}
cur1 = len1 >= len2?head1:head2;
cur2 = len1 >= len2?head2:head1;
for(int i = 1;i <= Math.abs(len1 - len2);i++) {
cur1 = cur1.next;
}
while(cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
//两个链表都有环,返回两链表第一个相交节点;若不相交返回null。
// 有三种情况
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
//第一种情况
if(loop1 == loop2) {
int len1 = 1;
int len2 = 1;
Node cur1 = head1;
Node cur2 = head2;
while(cur1.next != loop1) {
len1++;
cur1 = cur1.next;
}
while(cur2.next != loop2) {
len2++;
cur2 = cur2.next;
}
cur1 = len1 >= len2?head1:head2;
cur2 = len1 >= len2?head2:head1;
for(int i = 1;i <= Math.abs(len1 - len2);i++) {
cur1 = cur1.next;
}
while(cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
//第二种情况
Node cur1 = loop1.next;
while(cur1 != loop1) {
if(cur1 == loop2) {
//or return loop2;
return loop1;
}
cur1 = cur1.next;
}
//第三种情况
return null;
}
}