编写一个程序,找到两个单链表相交的起始节点。
示例:
如下面的两个链表:
在节点 c1 开始相交。
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
方法一:
思路如下:
判断两个单链表是否相交。当两链表地址一样的时候即相交。
判断的依据:地址一样,是Y类交叉。
难点就在于两链表的长度不一样,所以要先求二者长度的差值,让长的单链表先走,在判断即可。
代码如下:
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null; //此时没有交点
}
ListNode pL = headA;//永远指向长的单链表
ListNode pS = headB;//永远指向短的单链表
int lenA = 0;
int lenB = 0;
//求各链表的长度
//求的lenA lenB
while (pL != null) {
lenA++;
pL = pL.next;
}
while (pS != null) {
lenB++;
pS = pS.next;
}
pL = headA;
pS = headB;
//差值-》最长的单链表先走len步
int len = lenA - lenB;
if (len < 0) {
pL = headB;
pS = headA;
len = lenB - lenA;
}
//让pL先走len步
while (len > 0) {
pL = pL.next;
len--;
}
//开始一起走 (pL != pS ) {一人一步走}
while (pL != pS) {
pS = pS.next;
pL = pL.next;
}
if ( pL == null ){
return null;
}
return pL; //return pS;
}
public static void createCut //相交的链表
(ListNode headA, ListNode headB) {
headA.next = headB.next.next;
}
测试:
public static void main(String[] args) {
SingleList singleList = new SingleList();
SingleList singleList2 = new SingleList();
singleList.addLast(1);
singleList.addLast(2);
singleList.addLast(3);
singleList.addLast(10);
singleList.display();
singleList2.addLast(3);
singleList2.addLast(4);
singleList2.addLast(10);
singleList2.addLast(17);
singleList2.display();
createCut(singleList.head,singleList2.head);
ListNode node = getIntersectionNode(singleList.head,singleList2.head);
System.out.println(node.data);
}
//结果为
1 2 3 10
3 4 10 17
10
方法二:
上述方法虽然简单易懂,但有些冗余,急性子的人怕是很难静心看完,来看下一个方法:
思路:
定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差);两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
/**
定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部,
最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
两个指针等于移动了相同的距离, 有交点就返回,
无交点就是各走了两条指针的长度
**/
if(headA == null || headB == null) return null;
ListNode pA = headA, pB = headB;
/* 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头,
而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null == null*/
while(pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}
当然了,第二个方法虽然代码少,但还是需要自己仔细研究搞懂,否则还是第一种方法更靠谱一些。