编写一个程序,找到两个单链表相交的起始节点。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
思路一:暴力法
将A链中每个节点都和B中每个节点相比。
- 时间复杂度:O(mn)
- 空间复杂度:O(1)
思路二:使用哈希表
将A链中的节点都存到一个哈希表中,然后逐个对比B链中的节点是否在表中。第一个就是要返回的。
- 时间复杂度:O(m+n)
- 空间复杂度:O(n)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> hashSet = new HashSet<ListNode>();
ListNode aNode = headA;
ListNode bNode = headB;
while(aNode!=null){
hashSet.add(aNode);
aNode = aNode.next;
}
while(bNode!=null){
if(hashSet.contains(bNode)){
break;
}
bNode = bNode.next;
}
if(bNode!=null){
return bNode;
}
return null;
}
}
思路三:双指针法
我原来以为这个不行,以为相交之后还有分开的情况。不过看了看leetcode的介绍,发现相交就一直到尾了。所以可以用双指针,分别指向两个链表头节点。
链表A和B的长度可能不同,但是A+B = B+A,所以,当一个节点走到末尾时,再从另一个链表开始走,把对方的路再走一遍。然后他们相遇的点,一定就是相交点了。假如两链不相交,那么最终会在null处停下来。
class Solution{
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;
ListNode pA = headA, pB = headB;
while (pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}
不过要注意的是,要在链表的最后方放一个null,在等于null时再指向另一个链表,不然就会出现环!!!然后死循环