Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
题目:给定两个链表的头节点,判断两个链表是否相交,如果相交则返回相交的起始节点,否则返回null。
解题思路
本题和环形链表的思路类似,简单的思路是将headA和headB链表的节点一个个入HashSet,每次入集合都判断该节点是否已经在Set中,如果存在则直接返回当前节点,如果两个链表都遍历完了则返回null,可得如下代码:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
HashSet<ListNode> set = new HashSet<>();
while(headA!=null&&headB!=null){
if(set.contains(headA)){
return headA;
}else {
set.add(headA);
}
headA = headA.next;
if(set.contains(headB)){
return headB;
}else {
set.add(headB);
}
headB = headB.next;
}
while(headA!=null){
if(set.contains(headA)){
return headA;
}
set.add(headA);
headA = headA.next;
}
while(headB!=null){
if(set.contains(headB)){
return headB;
}
set.add(headB);
headB = headB.next;
}
return null;
}
代码的时间复杂度为,空间复杂度为。题目要求空间复杂度为,那么可以换一种思路,不使用额外的空间。
此时只需要保证两个链表保持相同的长度向后走,之后每走一步都判断一下两个节点是否相同,如果相同则是相交点,如果最终都走向了null则代表两个链表不相交,此时返回null即可。具体流程是:
首先分别计算俩个链表的长度,之后判断哪个链表长并且计算两个链表之间的差值,让长的链表走差值的距离之后,两个链表再同时走即可,可得代码如下:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = 0;
int lenB = 0;
ListNode curA = headA;
ListNode curB = headB;
while(curA!=null){
curA = curA.next;
lenA++;
}
while(curB!=null){
curB = curB.next;
lenB++;
}
int preStep = lenA-lenB;
if(preStep>0){
while(preStep>0){
headA = headA.next;
preStep--;
}
}
else if(preStep<0){
while (-preStep>0){
headB = headB.next;
preStep++;
}
}
while(headA!=null&&headB!=null){
if(headA==headB){
return headA;
}
headA = headA.next;
headB = headB.next;
}
return null;
}
上述代码的时间复杂度为,空间复杂度为。
还有一种方式不需要计算两个链表的长度,可以通过移动消除两个链表长度不一致的影响,思路如下:
设定两个指针preA和preB分别指向headA和headB,让preA和preB同时移动,当一个指针到null时,另一个指针剩下的路程即为两条链表的长度差,此时将已经走完的指针指向另一条指针,而等未走完的指针走完指向另一条链表,此时两个指针指向的链表的长度就能保持一致,之后往后走边走边判断即可,代码如下:
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;
}
时间复杂度,空间复杂度也是。