var getIntersectionNode = function(headA, headB) {
let a = headA, b = headB;
while(a != b) {
a = a != null ? a.next : headB;
b = b != null ? b.next : headA;
}
return a;
};
ListNode A = headA;
ListNode B = headB;
while (A != B) {
// 遍历链表,当一条链表遍历完成后,跳到另一条链表进行遍历
A = A == null ? headB : A.next;
B = B == null ? headA : B.next;
}
return A;
}
“`python
class Solution(object):
def getIntersectionNode(self, headA, headB):
a=headA
b=headB
//当它们相遇时,所指向的结点就是第一个公共结点
while a!=b:
a=a.next if a else headB
b=b.next if b else headA
return a
时间复杂度:O(M+N) M、N为链表l1和l2的长度
空间复杂度:O(1)
指针 A 先遍历完链表 headA ,再开始遍历链表 headB ,当走到 node 时,共走步数为:a+(b−c)
指针 B 先遍历完链表 headB ,再开始遍历链表 headA ,当走到 node 时,共走步数为:b+(a−c)
如下式所示,此时指针 A , B 重合,并有两种情况:a+(b−c)=b+(a−c)
若两链表 有 公共尾部 (即 c>0 ) :指针 A , B 同时指向「第一个公共节点」node 。
若两链表 无 公共尾部 (即 c=0 ) :指针 A , B 同时指向 null 。
因此返回 A 即可。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
A,B=headA,headB
while A!=B: #如果没有公共节点,那么两个指针交换跑道,最后都遍历到None,然后相等退出
A=A.next if A else headB # 如果A遍历完了,则到B上继续遍历
B=B.next if B else headA # 如果B遍历完了,则到A上继续遍历
return A #返回共同的节点,首次相遇的节点;巧妙的是,他们会同时相遇这个节点(相同的步长step=1,相同的长度distance=a+b-c)
时间复杂度:O(n+m-c)
空间复杂度:O(1)
引用一个题解的观点:
如果两链表的长度相等,只要从头开始查找到第一个相同节点就行啦,所以关键问题是解决两链表的长度不相等问题: (1)第一种方法是先统计出两链表的长度n1和n2,则只要让较长的链表指针先走n1-n2(假设n1>n2)步,之后同时出发即可 (2)第二种方法就是像这里的交换跑道,因为长度之和n1+n2是不变的,第一遍遍历到尾部时,再跑到另一个链表的头部,再从这个链表头部遍历,此时两指针到达尾部的距离就相等了。A = A.next if A else headB 而非 A = A.next if A.next else headB 相当于在链表尾部增设一个null节点,如果链表无相交节点,最后就遍历到null返回即可,无需单独考虑这种情况
ListNode * A = headA;
ListNode * B = headB;
while(A!= B)
{
A = A != nullptr? A->next:headB;
B = B != nullptr? B->next:headA;
}
return A;
时间复杂度:O(1), 空间复杂度:O(1)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if headA == None or headB == None:
return None
a = headA
b = headB
while a != b:
# connect back to the other LL
# if reached anyone's end but still didn't find.
a = a.next if a else headB
b = b.next if b else headA
return a
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
A, B = headA, headB
while A != B:
A = A.next if A else headB
B = B.next if B else headA
return A
“`java
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode A = headA, B = headB;
while (A != B) {
A = A != null ? A.next : headB;//能相遇就意味着走的路是重合的
B = B != null ? B.next : headA;
}
return A;
}
}
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
// 1.创建左右节点
ListNode* A = headA;
ListNode* B = headB;
// 2.A走完整个headA链表,走到headB然后遍历到结束或者相遇
// B走完整个headB链表,走到headA然后遍历到结束或者相遇
while (A != B) {
if (A != nullptr) {
A = A->next;
} else {
A = headB;
}
if (B != nullptr) {
B = B->next;
} else {
B = headA;
}
}
//3.返回节点
return A;
}
共以下 53 个回答
另一个思路
时间复杂度O(N) 空间O(1)
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode l1 = headA;
ListNode l2 = headB;
while (l1 != l2) {
l1 = (l1 null) ? headB : l1.next;
l2 = (l2 null) ? headA : l2.next;
}
return l1;
}
}
双指针遍历
双指针,有两个相交点,那必然两个指针的路程是一致的,交换一下即可
时间复杂度O(N)
空间复杂度O(1)
“`java
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
// 如果A/B为空,直接返回空
return null;
}
}
时间复杂度:o(a+b)
空间复杂度:o(1)
“`python
class Solution(object):
def getIntersectionNode(self, headA, headB):
a=headA
b=headB
//当它们相遇时,所指向的结点就是第一个公共结点
while a!=b:
a=a.next if a else headB
b=b.next if b else headA
return a
时间复杂度:O(M+N) M、N为链表l1和l2的长度
空间复杂度:O(1)
###
时间复杂度O(m+n);空间复杂度O(n)
考虑构建两个节点指针 A , B 分别指向两链表头节点 headA , headB ,做如下操作:
如下式所示,此时指针 A , B 重合,并有两种情况:a+(b−c)=b+(a−c)
因此返回 A 即可。
时间复杂度:O(n+m-c)
空间复杂度:O(1)
引用一个题解的观点:
针对方法一,先同步起点,先有个快指针走到
diff=abs(na-nb),然后同步走,相遇的点就是共同点。该方法缺点是需要先完整遍历A,B,得到两个链表的长度,然后再遍历到共同点。时间复杂度:O(a+b),a和b分别为两个链表的长度
空间复杂度:O(1)
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode f1=headA;
ListNode f2=headB;
while(f1!=f2){
//两条链表最后都指向了同一个 null (None)节点,代替了不相交的特殊情况。
//f1null 而不是 f1.nextnull
if(f1null){
f1=headB;
}else{
f1=f1.next;
}
if(f2null){
f2=headA;
}else{
f2=f2.next;
}
}
return f1;
}
}
“`java
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p = headA;
ListNode q = headB;
while(p!=q)
{
if(p!=null) p = p.next;
else p = headB;
}
时间复杂度O(n) 空间复杂度O(1)
ListNode * A = headA;
ListNode * B = headB;
while(A!= B)
{
A = A != nullptr? A->next:headB;
B = B != nullptr? B->next:headA;
}
return A;
时间复杂度:O(1), 空间复杂度:O(1)
时间复杂度:O(n), 空间复杂度:O(1)
优雅
解题思路:
我们可以使用两个指针l1和l2分别从两个链表的头部开始遍历。当某个指针到达链表末尾时,我们让它从另一个链表的头部重新开始。这样,当两个指针相遇时,就找到了第一个相交节点。这个方法之所以有效,是因为两个指针走过的总路程是相等的:链表A的长度 + 链表B的非公共部分 = 链表B的长度 + 链表A的非公共部分。所以如果有相交点,两个指针一定会在相交点相遇。如果没有相交点,两个指针最终都会变为nullptr。
时空分析:
时间复杂度:O(n),其中n是两个链表的长度之和。每个指针最多遍历两个链表各一次。
空间复杂度:O(1),只使用了两个指针变量。
代码实现:
“`C++
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
if (headA == nullptr || headB == nullptr) {
return nullptr;
}
// 初始化两个指针分别指向两个链表头部
ListNode* l1 = headA;
ListNode* l2 = headB;
};
“`
时间复杂度O(n),空间复杂度O(1)
用集合记录headA链表所有节点的地址
遍历headB,找到其中第一个存在于st的地址返回
T O(n), M O(m),m为headA链表长度
“`c++ st;
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set
while(headA){
st.insert(headA);
headA=headA->next;
}
while(headB){
if(st.count(headB)){
return headB;
}
headB=headB->next;
}
return nullptr;
}
“`
从各自的起点出发寻找相同的节点 如果有任意一个走完了还找不到就指向第二个继续找 直到二者全部走完
有一种构造了环的感觉 但实际上又不是环 在某个时间节点将两个链表连接了起来
time: O(m+n)
space: O(1)
时间复杂度O(m+n)
空间复杂度O1
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA null) return null;
if(headB null) return null;
ListNode A = headA;
ListNode B = headB;
}
时间复杂度:O(n+m),n 和 m 表示两个链表长度
空间复杂度:O(1)
“`C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(headA == nullptr || headB == nullptr) return nullptr;
ListNode* n1 = headA;
ListNode* n2 = headB;
while(n1!=n2){
if(n1!=nullptr){
n1 = n1->next;
}else{
n1 = headB;
}
if(n2!=nullptr){
n2 = n2->next;
}else{
n2 = headA;
}
}
return n1;
}
};
“`
打卡
好
class Solution {
public:
ListNode getIntersectionNode(ListNode *headA, ListNode *headB) {
if(!headA||!headB) return nullptr;
ListNode A=headA;
ListNode* B=headB;
while(!(!A&&!B)){
A=A?A->next:headB;
B=B?B->next:headA;
if(AB) return A;
}
return nullptr;
};
时间O(n)空间O(1)
题解
“java
双指针同时遍历,有交点时,走到底后移到另一个头部节点,一定会在第二次遍历中相遇,若无交点,p1=p2=null,最后跳出循环返回null
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
}
O(n) O(1)
“`java
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode A = headA, B = headB;
while (A != B) {
A = A != null ? A.next : headB;//能相遇就意味着走的路是重合的
B = B != null ? B.next : headA;
}
return A;
}
}
“`c++
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (!headA || !headB)
return nullptr;
};
//时间复杂度:O(m+n) m和n分别表示两个链表的长度
空间复杂度:O(1)
“`
双指针:
时间复杂度 o(n),空间复杂度 o(1)
相遇:class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
node1, node2 = headA, headB
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
auto pA=headA,pB=headB;
while(pA!=nullptr&&pB!=nullptr)
{
pA=pA->next,pB=pB->next;
}
};时间复杂度 o(n),空间复杂度 o(1)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(headA nullptr || headB nullptr) return nullptr;
ListNode *p = headA, *q = headB;
while(p != q){
p = p nullptr ? headB : p->next;
q = q nullptr ? headA : q->next;
}
return p;
}
};
时间复杂度 o(m + n),空间复杂度 o(1)
思路:成环互补逆搜索,相交为对称中心
“`golang
// 节点相交 和 节点值相等不是一回事
// 节点相交: 指的是两个链表在某个节点开始共享同一个内存地址
func getIntersectionNode(headA, headB *ListNode) *ListNode {
if headA == nil {
return nil
}
if headB == nil {
return nil
}
}
我用的时间好长,是因为Java吗()
时间复杂度O(n+m),空间复杂度O(1)
a.思路分析
1.定义两个探索的指针
2.由于A+B的路径对于B+A的路径和,如果遇到一个链表走完了可以指向下一个链表头节点
b.代码:
c.时间复杂度:o(m+n),m和n分别是链表a和b的长度;空间复杂度o(1),使用了常数级的额外空间。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int l1 = 0, l2 = 0;
ListNode * temp = headA;
while(temp){
l1++;
temp=temp->next;
}
temp = headB;
while(temp){
l2++;
temp=temp->next;
}
if(l1 != l2){
int t = abs(l1-l2);
if(l1>l2){
while(t!=0){
headA = headA->next;
t–;
}
}
else{
while(t!=0){
headB = headB->next;
t–;
}
}
}
while(headA && headB){
if(headA headB){
return headA;
}
else{
headA = headA->next;
headB = headB->next;
}
}
return NULL;
}
};
思路:先遍历一遍两个链表求出各自的长度,根据长度差调整较长链表的起点,使两个链表一样长,这时同时开始遍历,如果相交直接返回对应节点,如果全都遍历到结尾证明两者不想交。
时间复杂度O(n),空间复杂度O(0)。
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
let a = headA
let b = headB
while(a != b) {
if(a ! null) {
a = a.next
} else {
a = headB // 自身遍历完后从另一个链表头开始遍历
}
if(b ! null) {
b = b.next
} else {
b = headA
}
}
return a
};
思路:循环完自身后循环另一个链表,有重合点则会相遇,否则都为null时才相等
时间复杂度O(N)
空间复杂度O(1)
Definition for singly-linked list.
class ListNode:
def init(self, x):
self.val = x
self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
cur_a = headA
cur_b = headB
while(cur_a != cur_b):
if cur_a:
cur_a = cur_a.next
else:
cur_a = headB
if cur_b:
cur_b = cur_b.next
else:
cur_b = headA
return cur_a
时间复杂度O(n)
空间复杂度O(1)
思路就是双指针,通过经过其中一条链到结尾接入另一条链,最后的交点两者路程相同,就是公共点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA null || headB null) {
return null;
}
}
时间o(n)
空间o(1)
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA null || headB null) {
return null; // 如果任意一个链表为空,直接返回 null
}
}
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
// 1.创建左右节点
ListNode* A = headA;
ListNode* B = headB;
// 2.A走完整个headA链表,走到headB然后遍历到结束或者相遇
// B走完整个headB链表,走到headA然后遍历到结束或者相遇
while (A != B) {
};
时间复杂度 O(a+b)
空间复杂度 O(1)
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1=headA,p2=headB;
while(p1!=p2){
p1=(p1!=null)?p1.next:headB;
p2=(p2!=null)?p2.next:headA;
}
return p1;
}
}
时间O(N),空间O(1)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headAnull||headBnull) return null;
ListNode tmpA=headA;
ListNode tmpB=headB;
while(tmpA!=tmpB){
if(tmpAnull) tmpA=headB;
else tmpA=tmpA.next;
if(tmpBnull) tmpB=headA;
else tmpB=tmpB.next;
}
return tmpA;
}
}
思路:先判空,如果有至少一个链表为空,则直接返回null,当都不为空时使用双指针交叉遍历即可得到最终解。
时间复杂度O(n+m)
空间复杂度O(1)
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode l1 = headA, l2 = headB;
while(l1 != l2){
l1 = l1 != null ? l1.next : headB;
l2 = l2 != null ? l2.next : headA;
}
return l1;
}
}
时间:o(n)
空间:o(1)
本题相当于是在求链表相交时的节点,定义两个指针
pA和pB分别指向链表headA和headB的头节点,用于遍历两个链表,直至pA == pB。在循环中,如果pA或pB达到链表末尾(即其值等于null)时,则将其重定向到另一个链表的头节点,这样就可以保证遍历两个指针可以同时达到相交节点。当pA == pB时,退出循环,返回相交节点。如果没有相交节点,返回null。时间复杂度:O(m + n),需要遍历两个链表。
空间复杂度:O(1),使用了常数级的额外空间。
LCR 140. 训练计划 II(https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/)
时间复杂度 O(n)
class Solution { public ListNode deleteNode(ListNode head, int val) {
ListNode current = new ListNode(-1, head);
ListNode newHead = current;while(current != null){if(current.next.val == val){current.next = current.next.next;break;}current = current.next;}return newHead.next;}}class Solution {LCR 140. 训练计划 II(https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/)
思路: 快慢指针
时间复杂度 O(n)
public ListNode trainingPlan(ListNode head, int cnt) {// 双指针 两指针相差 cntListNode first = head;ListNode second = head;// second 向后 cnt 位for(int i = 0; i < cnt; i ++){second = second.next;}while(second != null){// second 指向null时 first 指向倒数第cnt个second = second.next;first = first.next;}return first;}}class Solution {LCR 142. 训练计划 IV(https://leetcode.cn/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof/)
时间复杂度 O(n)
public ListNode trainningPlan(ListNode l1, ListNode l2) {ListNode ans = new ListNode(-1, null);ListNode ans_head = ans;ListNode l1_temp = l1;ListNode l2_temp = l2;while(l1_temp != null && l2_temp != null){if(l1_temp.val < l2_temp.val){ans.next = l1_temp;l1_temp = l1_temp.next;ans = ans.next;}else{ans.next = l2_temp;l2_temp = l2_temp.next;ans = ans.next;}}if(l1_temp != null){// 将 剩余部分 接到后续ans.next = l1_temp;}if(l2_temp != null){// 将 剩余部分 接到后续ans.next = l2_temp;}return ans_head.next;}}class Solution {LCR 171. 训练计划 V(https://leetcode.cn/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/)
时间复杂度 O(n)
ListNode getIntersectionNode(ListNode headA, ListNode headB) {// 若存在公共链 则从最后到第一个公共部分长度相同// 首先将 A B 对齐// 统计链表长度int lenA = getLen(headA);int lenB = getLen(headB);if(lenA > lenB){// A 较长 A 首先向前 (lenA - lenB) 步 使得 A B 一样长int count = lenA - lenB;while(count != 0){headA = headA.next;count --;}}else if(lenA < lenB){// A 较长 A 首先向前 (lenA - lenB) 步 使得 A B 一样长int count = lenB - lenA;while(count != 0){headB = headB.next;count --;}}while(headA != null && headA.val != headB.val ){headA = headA.next;headB = headB.next;}return headA;}private int getLen(ListNode head){int count = 0;while(head != null){count ++;head = head.next;}return count;}`` }