两个可能有环链表相交找交点
-
这是几道题的一个综合
解题思路
- 首先我们先来分析一下无环情况如何找到交点
- 首先判断是否相交 --> 两个链表的最后一个节点是否相同,若相同则一定是相交的
- 若相交,找交点 --> 将链表差值得出,长链表先走差值这么多,然后两个链表一起走,第一个相等的节点就是交点
- 接下来我们分析如何判断链表有环
思路一、 遍历链表将节点一个一个放入set集合,当放入的节点重复了,就说明有环,若节点走到null说明无环
思路二、 使用快慢指针,链表有环快慢指针必然会重合,若无环快指针会走到null (ps: 这里的快慢指针指的是快节点走两步,慢节点走一步) - 接下来我们找到链表环的入口节点
思路一、使用set的方式,找到的节点就是入口节点
思路二、 使用快慢指针找到重合节点后,快指针从头开始一步一步走,慢指针继续向前,两个指针重合节点就是入口节点 - 接着我们分析有环链表相交的情况
- 两个链表都有环且不相交
- 两个链表都有环相交,交点不在环上,或正好在入口点
- 两个链表都有环相交,交点在环上
第二种情况 --> 这种情况和无环相交类似,只是快节点走到null改为快节点走到环入口点
第三种情况,第一种情况 --> 找到两个链表的入口点,让一个链表的节点继续走,如果走一圈又走回来了没有碰到另一个入口点说明为情况1,若遇到了说明为情况2
代码
思路梳理清楚之后开始写代码
class Node{
int value;
Node next;
public Node(int value){
this.value = value;
}
}
1.首先我们先来分析一下无环情况如何找到交点
private static Node findCrosserPoint(Node node1,Node node2) {
if(node1 == null || node2 == null) {
return null;
}
Node nodeN = node1;
Node nodeM = node2;
int n = 0;
while (nodeN.next != null){
n++;
nodeN = nodeN.next;
}
while (nodeM.next != null){
n--;
nodeM = nodeM.next;
}
if(nodeN != nodeM){
return null;
}
nodeN = n > 0 ? node1 : node2;
nodeM = nodeN == node1 ? node2 : node1;
n = Math.abs(n);
for (int i = 0; i < n; i++) {
nodeN = nodeN.next;
}
while(nodeN != null){
if(nodeN == nodeM) {
break;
}
nodeN = nodeN.next;
nodeM = nodeM.next;
}
return nodeN;
}
2/3. 接下来我们分析如何判断链表有环,有环返回入口点,无环返回null
private static Node isCycle(Node node) {
// 思路二。 使用快慢指针,链表有环快慢指针必然会重合,若无环快指针会走到null
if(node == null || node.next == null || node.next.next == null){
return null;
}
Node nodeF = node.next.next;
Node nodeS = node.next;
while(nodeF != nodeS) {
if(nodeF.next == null || nodeF.next.next == null) {
return null;
}
nodeF = nodeF.next.next;
nodeS = nodeS.next;
}
// 找到入口点
nodeF = node;
while(nodeF != nodeS) {
nodeF = nodeF.next;
nodeS = nodeS.next;
}
return nodeF;
}
4.我们分析有环链表相交的情况
private static Node findCrosser(Node node1,Node node2,Node loop1,Node loop2) {
if(node1 == null || node2 == null || loop1 == null || loop2 == null) {
return null;
}
if(loop1 == loop2) {
// 第二种情况 --> 这种情况和无环相交类似,只是快节点走到null改为快节点走到环入口点
Node nodeN = node1;
Node nodeM = node2;
int n = 0;
while (nodeN.next != loop1){
n++;
nodeN = nodeN.next;
}
while (nodeM.next != loop2){
n--;
nodeM = nodeM.next;
}
nodeN = n > 0 ? node1 : node2;
nodeM = nodeN == node1 ? node2 : node1;
n = Math.abs(n);
for (int i = 0; i < n; i++) {
nodeN = nodeN.next;
}
while(nodeN != null){
if(nodeN == nodeM) {
return nodeN;
}
nodeN = nodeN.next;
nodeM = nodeM.next;
}
} else {
Node node = loop1.next;
while(node != loop1) {
if(node == loop2){
return node;
}
node = node.next;
}
return null;
}
return null;
}
5.总方法连接起来
private static Node isCrosser(Node node1,Node node2) {
Node loop1 = isCycle(node1);
Node loop2 = isCycle(node2);
if(loop1 == null && loop2 == null) {
return findCrosserPoint(node1,node2);
}
if(loop1 != null && loop2 != null) {
return findCrosser(node1,node2,loop1,loop2);
}
// 一个有环一个无环必然不相交
return null;
}