题目
力扣题目地址,点此可直接跳转
给你两个单链表的头节点 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)