Write a program to find the node at which the intersection of two singly linked lists begins.
For example, the following two linked lists:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
begin to intersect at node c1.
Notes:
- If the two linked lists have no intersection at all, return
null
. - The linked lists must retain their original structure after the function returns.
- You may assume there are no cycles anywhere in the entire linked structure.
- Your code should preferably run in O(n) time and use only O(1) memory.
Credits:
Special thanks to @stellari for adding this problem and creating all test cases.
分析:题目要求是找到两个单链表最初始的共同节点。
方法一
Step1:统计A和B的长度;
Step2:比较链表A和B的长度,为保证后面的代码统一,如果A的长度比B大,则交换A和B的头结点;
Step3:先让长的B先走|lena-lenb|步;
Step4:让A和B同时走,直到A和B为null,或者遇到A和B相同的节点。
/*找两个单链表的交叉点*/
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {//时间复杂度是o(lena+lenb)
ListNode A = headA;
ListNode B = headB;
int lena = 0;
int lenb = 0;
/*Step1:统计A和B的长度*/
while(A!=null){
lena++;
A=A.next;
}
A = headA;
while(B!=null){
lenb++;
B=B.next;
}
B = headB;
/*Step2:比较链表A和B的长度,为保证后面的代码统一,如果A的长度比B大,则交换A和B的头结点*/
if(lena>lenb){
ListNode l = A;
A = B;
B = l;
}
/*Step3:先让长的B先走|lena-lenb|步*/
for(int i=0;i<Math.abs(lena-lenb);i++){
B=B.next;
}
/*Step4:让A和B同时走,直到A和B为null,或者遇到A和B相同的节点*/
while(A!=B){
A=A.next;
B=B.next;
}
return B;
}
方法二:理论上和我自己测试的都是正确的,但是在leetcode上提交之后却不通过。。。。。。。。。。。。。需要进一步考虑~~~~
Step1:两个链表同时向后走,找到最先走到链表末尾的节点;
Step2:让最先走到末尾的链表节点指向另外一个链表的头结点,然后判断新的长链表中是否有环,如果有环则返回入口节点,否则返回null。
public ListNode getIntersectionNode2(ListNode headA, ListNode headB) {//自己测试通过,但是leetcode提交不通过(暂时还不知道为什么????20151027)
ListNode A = headA;
ListNode B = headB;
ListNode C = new ListNode(0);
if(A==null || B==null){
return null;
}
/*Step1:两个链表同时向后走,找到最先走到链表末尾的节点*/
while(A.next!=null && B.next!=null){
A=A.next;
B=B.next;
}
/*Step2:让最先走到末尾的链表节点指向另外一个链表的头结点,然后判断新的长链表中是否有环,并返回入口节点*/
if(A.next == null){
A.next = headB;
C = detectCycle(headA);
}else{
B.next = headA;
C = detectCycle(headB);
}
return C;
}
/*如果一个链表中由环,则返回的是环的入口节点*/
public ListNode detectCycle(ListNode head) {
/*Step1:先找到链表中是否有环,有环的话通过快指针和慢指针找到其碰撞的节点*/
if(head == null || head.next == null){
return null;
}
ListNode slow = head;
ListNode fast = head.next;
while(fast!=null && fast.next!=null){
if(fast == slow){
break;
}
fast = fast.next.next;//每次fast走两步,slow走一步,如果有环,则fast和slow一定相遇
slow = slow.next;
}
if(fast != slow){//fast不等于slow,说明没有环
return null;
}else{
/*Step2:找入口节点:头结点到入口节点的距离等于碰撞点的下一个节点p到入口点的距离+(n-1)c,其中c表中环的长度*/
ListNode p = fast.next;//设置p为碰撞点的下一个节点
ListNode h = head;
while(h!=null && p!=null){
if(p == h){
break;
}
h=h.next;
p = p.next;
}
return h;
}
}