//查询相交链表的第一个节点
public class FindFirstIntersectNode {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node getIntersectNode(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node loop1 = getLoopNode(head1);
Node loop2 = getLoopNode(head2);
//如果head1和head2所在的链表各自都没有环,则判断二者是否相交
if (loop1 == null && loop2 == null) {
return noLoop(head1, head2);
}
//如果head1和head2所在的链表存在环,则判断二者是否相交,loop为自身存在环时自身的交点
if (loop1 != null && loop2 != null) {
return bothLoop(head1, loop1, head2, loop2);
}
return null;
}
//用于判断自身链表是否有环
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node n1 = head.next; // n1 -> slow
Node n2 = head.next.next; // n2 -> fast
while (n1 != n2) {
//如果n2存在下个节点或下下个节点为null则不存在环
if (n2.next == null || n2.next.next == null) {
return null;
}
n2 = n2.next.next;
n1 = n1.next;
}
//从二者碰撞节点和头节点开始走,二者再次碰撞的位置即为碰撞的节点
n2 = head; // n2 -> walk again from head
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
return n1;
}
因为如果二者相交且没有环,则只能是Y型,或者是I型(即二者是包含关系),但二者的共同点是终点相同
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
//n记录head1的链表的长度
//在此之前需要先获取head1和head2的长度,
while (cur1.next != null) {
n++;
cur1 = cur1.next;
}
while (cur2.next != null) {
n--;
cur2 = cur2.next;
}
//如果终点不同,则不相交
if (cur1 != cur2) {
return null;
}
//下面获取二者的交点
//n>0说明head1长度长于head2
//将cur1赋为较长的head,cur2为较短的head
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
//n取绝对值(此时n为二者的长度差)
//所以从长的
n = Math.abs(n);
//较长的链表提前前进n位
while (n != 0) {
n--;
cur1 = cur1.next;
}
//此时同步进行,就可以获得交点
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
//用于判断存在环时寻找交点
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
Node cur1 = null;
Node cur2 = null;
//如果二者自身的交点相同?
if (loop1 == loop2) {
cur1 = head1;
cur2 = head2;
int n = 0;
//比较head1所在链表和head2所在链表的长度
//统计head1到loop1的n
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop2) {
n--;
cur2 = cur2.next;
}
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;
//交点不同
} else {
//令cur1为head1的入环点下一位
cur1 = loop1.next;
//注意,如果
//遍历环,查看是否和head2的链表有交集,如果有则返回交点
while (cur1 != loop1) {
if (cur1 == loop2) {
return loop1;
}
cur1 = cur1.next;
}
return null;
}
}
public static void main(String[] args) {
// 1->2->3->4->5->6->7->null
Node head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
// 0->9->8->6->7->null
Node head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
// 1->2->3->4->5->6->7->4...
head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
head1.next.next.next.next.next.next = head1.next.next.next; // 7->4
// 0->9->8->2...
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next; // 8->2
System.out.println(getIntersectNode(head1, head2).value);
// 0->9->8->6->4->5->6..
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
}
}
链表——两个链表相交
这篇文章介绍了如何在Java中实现一个名为`FindFirstIntersectNode`的类,用于找到两个给定链表的第一个交点。方法包括判断链表是否有环,以及在无环或有环情况下找到交点的逻辑。示例代码展示了如何在特定链表结构中查找交点。
摘要由CSDN通过智能技术生成