题目
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/description/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路一:集合法
使用set集合(这个简单就不画图了)
1、创建一个Hashset
2、依次遍历链表A的节点,并存入集合中
3、遍历链表B的节点
4、如果B的某个节点在集合中存在,返回
代码
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
HashSet set = new HashSet(); // 集合,用来存储某个链表遍历的节点
while(headA!=null){ // 遍历headA链表
set.add(headA); // 我们这里将headA的节点存入set中
headA = headA.next; // 添加完毕后别忘记将headA指向下一个
}
while(headB!=null){ // 遍历headB链表
if(set.contains(headB)){ // 判断headB的节点是否存在于set结合中
return headB;
}
headB = headB.next; // 不在集合中,指向下一个
}
return null; // 遍历完都没有,返回null
}
}
说明:
1、空间复杂度:将一个链表节点均存储到set集合,空间复杂度为O(N)
2、时间复杂度:(set集合底层是红黑树,添加和查询的事件复杂度为O(logN))最坏情况下需要将另外一个链表都遍历一遍,所以时间复杂度为O(NlogN)
思路二:双指针法
从链表长度入手(直接看图)
代码
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lengthA = getLength(headA); // getLength方法需要自己写
int lengthB = getLength(headB);
// 判断headA和headB哪个长,让长的往后移动
if(lengthA>lengthB){ // headA长就先让headA往后走几步
headA = move(lengthA-lengthB,headA); // 调用移动方法
} else if(lengthB>lengthA){ // headB长就先让headB往后走几步
headB = move(lengthB-lengthA,headB); // 调用移动方法
}
// 此时两个链表的长度相等
while(headA!=null && headB!=null){
if(headA==headB){
return headA; // 这里返回谁都行
}
headA = headA.next;
headB = headB.next;
}
return null;
}
// 【方法】查询链表的长度
public int getLength(ListNode head){
int count = 0;
while(head!=null){
head = head.next;
count++;
}
return count;
}
// 【方法】根据链表长度差,移动链表
public ListNode move(int size,ListNode node){
while(size>0){
node = node.next;
size--;
}
return node;
}
}
说明:
1、空间复杂度:无额外的空间开辟,为O(1)
2、时间复杂度:最坏情况下需要将两个链表都遍历一遍为O(N)