求两个链表是否相交并返回相交的点,或者返回第一个相交的点
两个链表不相交是完全独立的,如果相交那么其中一部分必然是公共的,最容易的想到的结构是这样的:

这种普通链表如果想要求是否相交:
通过遍历找到两个链表的尾结点,如果这两个尾结点相等,代表这两个链表一定是相交的,因为相交就存在公共的尾结点。
public static NodeLinked findEnd(NodeLinked node){
while (node.next != null){
node = node.next;
}
return node;
}
// 找到链表1的尾结点
NodeLinked n1_end = findEnd(链表1);
// 找到链表2的尾结点
NodeLinked n2_end = findEnd(链表2);
if(n1_end == n2_end){
// 代表两个普通链表相交
}
但这只是普通的链表,还有一种带环的链表结构,所以除了普通链表的情况还有带环链表的情况:

针对带环链表的处理,把环的入口所在节点往后的所有节点全部砍掉,将它退化成相交的两个普通链表就能复用之前的逻辑。

所以需要先找到环的入口,求一个链表的环的入口:
快指针走两步,慢指针走一步,两个指针相遇代表有环,然后快指针从头部开始和慢指针同时开始走,都只走一步,最终相遇就是入口。
// 如果是一个有环的链表,那么返回环的入口节点
// 如果是一个无环的链表,返回链表的尾结点
public static NodeLinked findEnd(NodeLinked node){
NodeLinked slow = node,fast = node;
do{
if(fast != null && fast.next != null){ // 快指针每次走两步,当快指针遇到NULL的时候意味着走到了结尾没有环,
// 但是反过来判断:不等于NULL的时候让快指针走,为了快指针走完的的时候不让程序结束,直到慢指针走完
fast = fast.next.next;
}
// 慢指针走完就结束
if(slow.next == null){
break;
}
slow = slow.next;
} while (slow != fast); // 当快慢指针相遇,意味着有环
if(slow == fast){
System.out.println("这是一个带环链表,"+slow.value);
fast = node; // 找到环的入口
do {
fast = fast.next;
slow = slow.next;
}while (fast != slow);
}
}
// 找到链表1的尾结点或环入口
NodeLinked n1_end = findEnd(链表1);
// 找到链表2的尾结点或环入口
NodeLinked n2_end = findEnd(链表2);
// 尾结点相等或环入口相等
if(n1_end == n2_end){
// 代表两个普通链表或带环链表相交
}
这样就解决了上边四种情况,然后还有一种特殊的情况:

一个环,两个链表在同一个环上不同的位置,那么if(n1_end == n2_end)不相等但是也属于相交,所以让链表1的环入口节点n1_end向前移动,如果能找到链表2的环入口节点则代表也属于相交。
同时如果求两个链表第一个相交的点,先计算链表的长度,让最长的链表把相差的距离走完,再一起移动直到相遇就是第一个相交的点
package com.algorithm.question;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* 求两个链表是否相交并返回相交的点,这两个链表有可能有环的存在
*/
public class LinkedListTwoIsXJ {
static LinkedListTwoIsXJ linkedListTwoIsXJ = null;
static NodeLinked genera = null;
static NodeLinked n1_insert = null;
static NodeLinked n2_insert = null;
public static void main(String[] args) {
linkedListTwoIsXJ = new LinkedListTwoIsXJ();
LinkedListTwoIsXJ.NodeLinked n1 = linkedListTwoIsXJ.new NodeLinked();
LinkedListTwoIsXJ.NodeLinked n2 = linkedListTwoIsXJ.new NodeLinked();
//1 两条普通的链表相交-验证
// initgenera();
// n1 = init(n1);
// n2 = init2(n2);
//2 两条带环的链表相交-验证
// initgeneraTwo();
// n1 = init(n1);
// n2 = init2(n2);
// 3 特殊环的链表相交-验证
initgeneraTree();
n1 = init(n1);
n2 = init2(n2);
NodeLinked n1_end = findEndNode(n1);
NodeLinked n2_end = findEndNode(n2);
NodeLinked xjNode = null;
if(n1_end == n2_end){ // 两条链表相交(两条普通链表或者带环链表)
System.out.println("两条普通链表或者带环链表-相交");
xjNode = findFirstXJ(n1,n2,n1_end,n2_end);
}else{
System.out.println("两条特殊链表相交或者不相交");
xjNode = findFirstXJCycle(n1,n2,n1_end,n2_end);
}
System.out.println(xjNode);
if(xjNode != null){
System.out.println(xjNode.value);
}
}
public static NodeLinked findEnd(NodeLinked node){
while (node.next != null){
node = node.next;
}
return node;
}
/**
* 找到两条链表相交的第一个点,包含两条普通链表相交和带环链表相交,
* 如果是带环链表,n1_end和n2_end是环的入口,以入口作为链表结尾,等同于两条普通链表处理
* @param n1
* @param n2
* @param n1_end
* @param n2_end
* @return
*/
public static NodeLinked findFirstXJ(NodeLinked n1,NodeLinked n2,NodeLinked n1_end,NodeLinked n2_end){
NodeLinked temp_n1 = n1;
NodeLinked temp_n2 = n2;
Integer size_n1 = 0,size_n2 = 0;
// 求链表1的总长度
while (temp_n1 != n1_end){
size_n1++;
temp_n1 = temp_n1.next;
}
// 求链表2的总长度
while (temp_n2 != n2_end){
size_n2++;
temp_n2 = temp_n2.next;
}
// 如果链表1更长,那么往前移动直到相等
temp_n1 = n1;
while (size_n1 > size_n2){
size_n1--;
temp_n1 = temp_n1.next;
}
// 如果链表2更长,那么往前移动直到相等
temp_n2 = n2;
while (size_n2 > size_n1){
size_n2--;
temp_n2 = temp_n2.next;
}
// 长度相等的两个链表,往前移动找到第一个相交的点
while (temp_n1 != temp_n2){
temp_n1 = temp_n1.next;
temp_n2 = temp_n2.next;
}
return temp_n1;
}
public static NodeLinked findFirstXJCycle(NodeLinked n1,NodeLinked n2,NodeLinked n1_end,NodeLinked n2_end){
NodeLinked temp = n1_end;
// 进入这个方法的条件是:两个链表完全不想交 || 两个链表特殊相交于一个环上
// 如果两个链表完全不想交:
// -- 那么普通链表需要判断是否到达结尾:temp != null
// -- 带环的链表判断是否在环内循环,避免死循环: temp != n1_end
// 如果两个链表相交,从n1_end上往前移动一定能遇到n2_end
do {
if(temp == n2_end){
return n1_end;
}
temp = temp.next;
}while(temp != null && temp != n1_end);
return null;
}
/**
* 如果链表有环就返回环的入口,如果链表没有环就返回最后一个节点
* @param node
* @return
*/
public static NodeLinked findEndNode(NodeLinked node){
NodeLinked slow = node,fast = node;
do{
if(fast != null && fast.next != null){ // 快指针每次走两步,当快指针遇到NULL的时候意味着走到了结尾没有环,
// 但是反过来判断:不等于NULL的时候让快指针走,这样为了快指针走完的的时候不让程序结束,直到慢指针走完
fast = fast.next.next;
}
// 慢指针走完就结束
if(slow.next == null){
break;
}
slow = slow.next;
} while (slow != fast); // 当快慢指针相遇,意味着有环
if(slow == fast){
System.out.println("这是一个带环链表,"+slow.value);
fast = node; // 找到环的入口
do {
fast = fast.next;
slow = slow.next;
}while (fast != slow);
}
return slow;
}
public static NodeLinked findEndNodeForSet(NodeLinked node){
Set<NodeLinked> set = new HashSet<>();
NodeLinked pre = node;
while (node != null){
if(set.contains(node)){
return node;
}
set.add(node);
pre = node;
node = node.next;
}
return pre;
}
/**
* 构造链表1的测试数据
* @param headInit
* @return
*/
public static NodeLinked init(NodeLinked headInit){
LinkedListTwoIsXJ.NodeLinked nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 4;
if(n1_insert != null){
nodeLinked.next = n1_insert;
}else if(genera != null){
nodeLinked.next = genera;
}
headInit = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 3;
nodeLinked.next = headInit;
headInit.pre = nodeLinked;
headInit = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 2;
nodeLinked.next = headInit;
headInit.pre = nodeLinked;
headInit = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 1;
nodeLinked.next = headInit;
headInit.pre = nodeLinked;
headInit = nodeLinked;
return headInit;
}
/**
* 构造链表2的测试数据
* @param headInit
* @return
*/
public static NodeLinked init2(NodeLinked headInit){
LinkedListTwoIsXJ.NodeLinked nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 4;
if(n1_insert != null){
nodeLinked.next = n2_insert;
}else if(genera != null){
nodeLinked.next = genera;
}
headInit = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 2;
nodeLinked.next = headInit;
headInit.pre = nodeLinked;
headInit = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 3;
nodeLinked.next = headInit;
headInit.pre = nodeLinked;
headInit = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 5;
nodeLinked.next = headInit;
headInit.pre = nodeLinked;
headInit = nodeLinked;
return headInit;
}
/**
* 构造一个普通的公共链表
*/
public static NodeLinked initgenera() {
LinkedListTwoIsXJ.NodeLinked nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 14;
genera = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 13;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 7;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 8;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
return genera;
}
/**
* 构造一个带环的公共链表
* @return
*/
public static NodeLinked initgeneraTwo() {
LinkedListTwoIsXJ.NodeLinked nodeLinked = linkedListTwoIsXJ.new NodeLinked();
LinkedListTwoIsXJ.NodeLinked end = linkedListTwoIsXJ.new NodeLinked();
end.value = 14;
genera = end;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 13;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 7;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
end.next = nodeLinked; // 加上环 14->7
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 8;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
return genera;
}
/**
* 构造一个圆环的链表
* @return
*/
public static NodeLinked initgeneraTree() {
LinkedListTwoIsXJ.NodeLinked nodeLinked = linkedListTwoIsXJ.new NodeLinked();
LinkedListTwoIsXJ.NodeLinked end = linkedListTwoIsXJ.new NodeLinked();
end.value = 14;
genera = end;
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 13;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
n1_insert = nodeLinked; // 链表1的插入点
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 7;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
n2_insert = nodeLinked; // 链表2的插入点
nodeLinked = linkedListTwoIsXJ.new NodeLinked();
nodeLinked.value = 8;
nodeLinked.next = genera;
genera.pre = nodeLinked;
genera = nodeLinked;
end.next = nodeLinked; // 加上环 14->8
return genera;
}
class NodeLinked{
LinkedListTwoIsXJ.NodeLinked next;
LinkedListTwoIsXJ.NodeLinked pre;
Integer value;
}
}
版权声明:本文为u011123890原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。