def getInterssectionNode(headA:ListNode,headB:ListNode)->ListNode:
'''
方法1:求两个链的长度差,让长的先走"长度差"步,此时两个指针在同时走就是相当于在两个链尾部对其的情况下在同时走
方法2:因为是单链条(a,b)有相交,所以如果有两个指针x,y,一个指针先走a个节点再走b个节点,另一个指针先走b个节点再走a个节点
两个指针的总路长是一样的(两条路径一定数量是对其的,因为长度一样,而且a和b又有重合的部分,所以两条对其的路后面几个节点是重合的),所以一定会在某个节点相遇后,后面的节点一直重合
例如:输入intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
指针a走:09124324
指针b走:32409124
倒数的2就是相交的节点
这里实现方法2
Args:
headA:
headB:
Returns:
'''
if (not headB) or (not headA):
return None
first = headA
second = headB
while first != second:
# 说明此时a链已经走完了,但还没有找到交点,就换b链走
# if not first:
# first = headB
# # 说明此时b链已经走完了,但还没有找到交点,就换a链走
# elif not second:
# second = headA
# else:
# first = first.next
# second = second.next
first = first.next if first else headB
second = second.next if second else headA
return first
var getIntersectionNode = function(headA, headB) {
let a = headA;
let b = headB;
while(a != b) {
a = a != null ? a.next : headB;
b = b != null ? b.next : headA;
}
return a;
};
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode a = headA;
ListNode b = headB;
while (a != b){
a = a == null? headA : a.next;
b = b == null? headB : b.next;
}
return a;
}
}
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
p,q = headA,headB
while p != q:
p = p.next if p else headB
q = q.next if q else headA
return p
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
#判空
# if not headA and headB:
# return null
#初始化
A = headA
B = headB
#循环链表,如果A(B)走到末尾则继续走HeadB(HeadA)链表,知道相交
while A != B:
A = A.next if A else headB
B = B.next if B else headA
return A
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int p1 = ListLength(pHead1);
int p2 = ListLength(pHead2);
ListNode res = null;
if(p1>=p2){
res = Move(pHead1,pHead2,p1,p2);
}else{
res = Move(pHead2,pHead1,p2,p1);
}
return res;
}
public ListNode Move(ListNode fast,ListNode slow,int fastL,int slowL){
int n = fastL-slowL;
for(int i=0;i<n;i++){
fast = fast.next;
}
while(fast!=null && slow != null && fast != slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
public int ListLength(ListNode list){
int n =0;
ListNode cur = list;
while(cur!=null){
n++;
cur = cur.next;
}
return n;
}
}
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null)
return null;
ListNode A = headA;
ListNode B = headB;
int a = 0, b = 0;
/*
while(A != B){
A = A == null ? headB : A.next;
B = B == null ? headA :B.next;
}
return A;
*/
while(A != null){
a += 1;
A = A.next;
}
while(B != null){
b += 1;
B = B.next;
}
if(a >= b){
A = headB;
B = headA;
int temp = b;
b = a;
a = temp;
}else{
A = headA;
B = headB;
}
int l = b - a;
for(int i = 0; i < l; i++){
B = B.next;
}
while(A != null){
if(A == B){
return A;
}
A = A.next;
B = B.next;
}
return null;
}
}
共以下 87 个回答
拼接法
拼接的时候,以 $px != null$ 为分界线,否则循环无法停止
时间复杂度:O(m+n) 两个链表长度之和
空间复杂度:O(1)
时间复杂度O(m+n)
空间复杂度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 == NULL || headB == NULL)
return NULL;
ListNode *p = new ListNode(-1);
ListNode *q = new ListNode(-2);
p = headA;
q = headB;
};
时间复杂度:O(m+n)
空间复杂度:O(1)
时O(1)空间O(m+n)
时O(1)空间O(m+n)
时间o(m+n);空间o(1)
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1=headA;
ListNode p2=headB;
while(p1!=p2){
if(p1null){
p1=headB;
}
else{
p1=p1.next;
}
if(p2null){
p2=headA;
}
else{
p2=p2.next;
}
}
return p2;
}
}
1,其实就是创建两个指针,分别遍历两个链表,每个指针遍历完自己的链表后再遍历另一个链表,如果链表后有重合的部分,而每个指针除了走过重合的部分外,其实分别走了一下没重合的链表部分,所以当两个指针走完之后,必为重合的那个节点。若无重合部分,两指针会指向空。
2,时间复杂度O(m+n) 空间复杂度O(1)
时间复杂度:O(n+m)
空间复杂度:O(1)
复杂度:
时间复杂度:O(m+n)
空间复杂度:O(1)
思路:
哈希表解法:哈希表的方式就是遍历链表a并且把每个节点存入到哈希表中,在遍历链表b的时候去哈希表中取,如果有存在于哈希表中就找到了第一个公共节点
因此使用双指针法进行解决
● 时间复杂度:O(n)
● 空间复杂度:O(1)
时间复杂度O(m+n)
空间复杂度O(1)
1、只要存在公共节点,那么a走完接着去走b,b走完接着去走a,他们一定会相遇。(本质原因还是说不太清)
2、时间复杂度O(n+m),空间复杂度O(1)
时间复杂度o(m+n)
空间复杂度o(m)
俩个链表不停的去走互相走过对方的位置就可以找到相交的节点
1、遍历第一个链表,存入一个容器中,在遍历第二个链表,如果节点在容器中已经存在,则从该节点开始往后是两个链表的重复部分
2、时间复杂度:O(m+n),其中 m 和 n 是分别是链表 headA 和 headB 的长度。需要遍历两个链表各一次。
空间复杂度:O(m),其中 m 是链表 headA 的长度。需要使用哈希集合存储链表 headA 中的全部节点。
时间复杂度 n
空间复杂度 1
//双指针?
class Solution {
public:
int fun(ListNode* head){
if(!head) return 0;
return 1+fun(head->next);
}
ListNode getIntersectionNode(ListNode *headA, ListNode *headB) {
int numa=fun(headA);
int numb=fun(headB);
if(numb>numa){
swap(numa,numb);
swap(headA,headB);
}
int sub=numa-numb;
ListNode a=headA,* b=headB;
while(sub–) a=a->next;
while(a){
if(ab) return a;
a=a->next;
b=b->next;
}
return nullptr;
}
};
看了一下双指针题解,确实简单,奈何我想不到
时间复杂度O(n)
空间复杂度O(1)
时间复杂度:O(m+n),其中m,n分别为链表的长度
空间复杂度:O(1)
解体思路:使用双指针分别指向两个链表,循环完自己链表后指向另一个链表的head,当对应val相等时,此时两指针相遇,得到公共节点
时间复杂度:O(m+n),每个指针都遍历了链表1+链表2
空间复杂度:O(1)
时间复杂度:O(n+m)
空间复杂度:O(1)
两个链表合起来遍历
时间复杂度O(N+M) n m分别是链表长度
空间复杂度为O(1)
时间复杂度O(m+n)
看了视频学到了思路,使用两个指针遍历两个链表,如果访问到了null节点,就接着访问另一条链表,相当于是6+4+null=4+6+null的感觉,各走相同的路一定能找到相交处,找不到就是一起走到了null(也相等了),返回就行。
时间复杂度O(m+n)
空间复杂度O(1)
压哨打卡(:
注意访问到null节点直接赋值,不要再使用->next了。
思路:遍历完链表 A 之后开始遍历链表 B,遍历完链表 B 之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起
时间复杂度 :O(a + b)
空间复杂度 :O(1)
时间复杂度: O(m+n)
空间复杂度:O(1)
思路:双指针暴力解
代码
时间复杂度:O(N)
空间复杂度:O(1)
思路一:先遍历一个链表,将遍历的节点加入到集合中,再开始遍历第二个链表,第一次在集合中出现的节点就是两个链表的第一个公共节点。时间复杂度O(N),空间复杂度O(N)。
思路二:统计两个链表的长度,让长链表先走两个链表长度的差值步,然后和短链表一起走,边走边判断两个链表的节点值是否相等,相等的节点就是两个链表的第一个公共节点。时间复杂度O(N),空间复杂度O(1)。
思路三:双指针法。有链表A、链表B,指针pa指向A的头节点,指针pb指向B的头节点,两个指针每一次都往后走一步,当指针pa走完链表A后,从链表B的头节点走。指针pb同理,直到pa和pb指向的两个节点相同就是两个链表的第一个公共节点。给出简单证明:链表A的头节点距第一个公共节点有a步,链表B的头节点距第一个公共节点有b步,第一个公共节点距尾节点有k步,如果a=b,那么pa,pb的第一次遍历就找到公共节点。如果a!=b,那么pa走a+k+b步,pb走b+k+a步,这时两个指针也到第一个公共节点。时间复杂度O(N),空间复杂度O(1)。
给出双指针法的实现
题解
时间复杂度为O(N+M)
空间复杂度为O(1)
下面是代码
注意:当链表A的指针到链表A结尾时,则接着指向链表B的头节点的语法
以上双链表,利用a+b+c
时间:O(n)
空间:O(1)
遍历链表headA,将其每个节点加入哈希表中,然后遍历链表B,判断节点是否在哈希集合中
时间复杂度:O(m+n)
空间复杂度:O(m)
思路:本题时快慢指针的变体,先让长的链表提前走(长链表长度-短链表长度)步,
然后两个链表一起遍历,当遍历到值相同的节点时返回,此时时第一个公共节点。
1. 写一个循环遍历函数findListLength(ListNode l);返回值是int, 用于返回链表长度。
2. 写一个move函数, 参数1是长的链表,参数2是短的链表,参数3是长链表的长度,参数4是短链表的长度,长度用于计算快指针提前走几步,move函数内的任务和前面Offer22中的内容相似,快指针提前走了几步以后,快慢指针再一起遍历。
3. 用Step1中得到的链表长度判断输出进来的两个链表谁长,根据长度来决定调用step2中move函数的参数位置。
4. 返回
时间复杂度O(n)
空间复杂度O(1)
时间复杂度:O(m+n)
空间复杂度:O(1)
额
我再去看几遍
示例1中两个链表的1是val,是值相同,地址不同。一开始还在想为什么1没相交。直接找。
快慢指针先判断有环没,并且记录第一次相遇地点;然后有环的话fast从头结点一步步走,low继续走,检查相遇节点
思路:
链表节点相等,即为二者地址相同而非所存数值相同
若两个链表存在公共节点,可以依次遍历比较节点是否相等
两个链表除去公共部分可能一长一短,所以遍历两次,长+公共+短=短+公共+长 之后首次相遇即为首个公共节点
遍历+第二次遍历使用快慢指针
时间复杂度O(n)空间复杂度O(1)
时间复杂度 O(a+b)
空间复杂度O(1)
时间复杂度 O(a + b) 最差 需要跑完两个链表
注意点: 在没有公共节点的时候,是把null 作为公共节点退出循环 然后返回 null
时间O(n+m), 空间O(1)
第一种是看题解的,想法就是 两个链表至多走m+n步,有就是有,无就是无
两种方法都写了一下,给出的确实代码量少很多。时间复杂度也基本相同。
先计算两个链表的长度,指向长链表的指针向后指到和短链表同样长度的位置
然后开始对比,相同则为第一个公共节点
// HashSet.contains() 可以判断哈希表里是不是有当前值 sites = new HashSet ();
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
HashSet
ListNode cuaA = headA, cuaB = headB;
while(cuaA!=null){
sites.add(cuaA);
cuaA = cuaA.next;
}
while(cuaB!=null){
if(sites.contains(cuaB)){
return cuaB;
}
cuaB = cuaB.next;
}
return null;
}
}
方法一:
方法二:
第一天第四题
把两个链表接起来,这样长度就一样了,这样要么交汇要么最后为空
两个指针要么在交汇处相遇,要么就是在null相遇,所以可以直接返回
让两个指针走相同的距离
能相遇的条件就是走相同的步数
昨天刚写
利用技巧,当到达链表结尾时接入另一条链表可以判断两条链表是否相交,并可以覆盖不相交的情况,即此时p1、p2都为null