问题描述:
给定两链表的头结点,判断两链表是否存在公共部分(相交),若相交返回相交的第一个节点。
经分析发现该问题可以分成如下两个子问题进行解决。
子问题一:两无环链表是否相交
算法一:假设list1长度为L1,list2长度为L2,假设公共部分长为m,由L1 + L2 - m = L2 + L1 -m可知第一路先遍历list1,再遍历list2,第二路先遍历list2再遍历list1,若存在结点在遍历到L1 + L2 - m时两链表值相同,该位置即为相交的第一个节点,若无公共部分,则会使得两个链表全遍历完。
算法一代码实现如下:
public static Node<Character> selution(Node<Character> head1, Node<Character> head2){
Node<Character> pointer1 = head1;
Node<Character> pointer2 = head2;
boolean flag1 = true, flag2 = true;
while (pointer1 != pointer2) {
if(flag1 && pointer1.next == null) {
pointer1 = head2;
flag1 = false;
}else {
pointer1 = pointer1.next;
}
if(flag2 && pointer2.next == null) {
pointer2 = head1;
flag2 = false;
}else {
pointer2 = pointer2.next;
}
}
return pointer1;
}
算法二:先遍历两链表获得两链表的长度,叫L1,L2(不妨令L1>L2),先让指向list1的指针向前移动L1-L2的位置,然后两指针一起移动,若存在公共节点则一定会出现两指针指向同一个节点的情况,此时该节点即为所求。
算法二代码如下:
public static Node<Character> selution1(Node<Character> head1, Node<Character> head2){
int length1 = 0, length2 = 0;
for (Node<Character> p = head1; p != null; p = p.next, length1++) {};
for (Node<Character> p = head2; p != null; p = p.next, length2++) {};
Node<Character> pLong, pShort;
int diff = Math.abs(length1 - length2);
if (length1 > length2) {
pLong = head1;
pShort = head2;
} else {
pLong = head2;
pShort = head1;
}
//长的先走diff
for(int i = 0; i < diff; i++, pLong = pLong.next) {};
for(; pLong != pShort; pLong = pLong.next, pShort = pShort.next) {};
return pLong;
}
子问题二:两有环链表是否相交
问题分析:对于两有环链表可能会出现如下三种情形:
上述三种情形中第一种为两链表入环结点相同,后两种入环结点不同。
因此可以采取如下的算法:
第一步: 获得两链表的入环结点
第二步:如两入环结点相同,该问题就可以转化为无环链表的相交结点问题,只不过此时的最后一个结点为相交结点,之前的为null而已。如入环结点不同,则可以从list1的入环结点往下遍历,遍历过程中能遇到list2的入环结点则可得两链表相交,两入环结点均可作为相交的第一个节点,否则不相交。
实现代码如下:
public class LoopListCommonElement {
public static Node<Integer> selution(Node<Integer> head1, Node<Integer> head2){
Node<Integer> loopHead1 = LoopList.selution1(head1);
Node<Integer> loopHead2 = LoopList.selution1(head2);
if (loopHead1 != loopHead2) {
Node<Integer> pTemp = loopHead1.next;
while (pTemp != loopHead1) {
if (pTemp == loopHead2) {
break;
}
pTemp = pTemp.next;
}
if (pTemp == loopHead2) {
return pTemp;
}else {
return null;
}
}else { // 入环结点相同的情况
return findCommonHead(head1, head2, loopHead1);
}
}
public static Node<Integer> findCommonHead(Node<Integer> head1,
Node<Integer> head2, Node<Integer> end){
int length1 = 0, length2 = 0;
for (Node<Integer> p = head1; p != end; p = p.next, length1++) {};
for (Node<Integer> p = head2; p != end; p = p.next, length2++) {};
Node<Integer> pLong, pShort;
int diff = Math.abs(length1 - length2);
if (length1 > length2) {
pLong = head1;
pShort = head2;
} else {
pLong = head2;
pShort = head1;
}
for(int i = 0; i < diff; i++, pLong = pLong.next) {};
for(; pLong != pShort; pLong = pLong.next, pShort = pShort.next) {};
return pLong;
}
至此,问题解决。(q:别急还有一个链表有环一个链表无环的情况你没考虑,ps:我赌他们一定不相交你信不信)