1.拼接两个字符串
先看下面的链表A和B:
A: 0-1-2-3-4-5
B: a-b-4-5
如果分别拼接成AB和BA会怎么样呢?
AB:0-1-2-3-4-5-a-b-4-5
BA:a-b-4-5-0-1-2-3-4-5
我们可以看出,A和B的公共节点也是AB和BA的公共节点
我们假定A和B有相交的位置,以交点为中心,可以将两个链表分别分为left_a和right_a,left_b和right_b这样四个部分,并且right_a和right_b是一样的,这时候我们拼接AB和BA就是这样的结构:代码如下:
/**
*拼接两个链表求公共节点
* @param pHead1 需要求第一个公共子节点的链表头结点
* @param pHead2 需要求第一个公共子节点的链表头结点
* @return
*/
//拼接两个字符串
public listNode findFirstCommonNode1(listNode pHead1, listNode pHead2){
if(pHead1==null||pHead2==null){
return null;
}
listNode node1=pHead1;
listNode node2=pHead2;
while(node1!=node2){
node1=node1.next;
node2=node2.next;
//注意node1!=node2的判断必须加,因为当没有公共节点时,会出现node1和node2同时是null的情况
//而下面的对于node1和node2为空的判断导致在对while的条件判断时,node1和node2不可能为空,所以
//需要另外加if(node1!=node2)的判断,以便于while循环判断时出现node1=node2=null的情况跳出循环
if(node1!=node2){
//一个链表访问完跳到另一个链表
if(node1==null){
node1=pHead2;
}
if(node2==null){
node2=pHead1;
}
}
}
return node1;
}
其中对于循环中if(node1!=node2)的判断的解释代码中注释已经提及
2.差和双指针
我们再看另一个使用差和双指针来解决问题的方法。假如公共子节点一定存在第一轮遍历,假设La长度为L1,Lb长度为L2.则|L2-L1|就是两个的差值。第二轮遍历,长的先走|L2-L1|,然后两个链表同时向前走,结点一样的时候就是公共结点了。
例如下图中,一条链表的长度为6,另一条的长度为5,差值为1,我们想要做的实际上是,让两个链表分别在a2和b1时同时走,此时它们距离第一个公共节点的距离相等,当第一次出现节点一样的情况时,该节点就是第一个公共节点
代码如下
/**
* 差和双指针法求两个链表的第一关公共节点
* @param pHead1 一个链表的头指针
* @param pHead2 另一个链表的头指针
* @return
*/
//差和双指针
public listNode findFirstCommonNode2(listNode pHead1, listNode pHead2) {
if(pHead1==null||pHead2==null){
return null;
}
listNode node1=pHead1;
listNode node2=pHead2;
int length1=0,length2=0;
//分别遍历两个链表求出长度
while(node1!=null){
node1=node1.next;
length1++;
}
while(node2!=null){
node2=node2.next;
length2++;
}
node1=pHead1;
node2=pHead2;
if(length1>length2){
for(int i=0;i<length1-length2;i++){
node1=node1.next;
}
}else{
for(int i=0;i<length2-length1;i++){
node2=node2.next;
}
}
while(node1!=null){
if(node1==node2){
return node1;
}
node1=node1.next;
node2=node2.next;
}
return node1;
}