Open azl397985856 opened 2 years ago
Thoughts
Code
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return headA == null ? headB : headA;
}
ListNode pa = headA, pb = headB;
while (pa != pb) {
pa = pa == null ? headB : pa.next;
pb = pb == null ? headA : pb.next;
}
return pa;
}
Complexity
我走完我的路,就去走你的路,我一共走了我+你的路;
你走完你的路,也来走我的路,你一共走了你+我的路;
这意味着我们走的路其实是一样多,如果两条路存在交点,那一定会遇见。
/**
* 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 *ptr1=headA;
ListNode *ptr2=headB;
while(ptr1!=ptr2){
ptr1=(ptr1==nullptr?headB:ptr1->next);
ptr2=(ptr2==nullptr?headA:ptr2->next);
}
return ptr1;
}
};
时间复杂度:O(A链长度+B链长度)
空间复杂度:O(1)
判断两个链表长度,将长的剪成短的(因为,如果有相交节点,那么相交后的节点长度相同,所以截取前半段共同行走,就能找到相交点)
func getIntersectionNode(headA, headB *ListNode) *ListNode {
if headA == nil || headB == nil{
return nil
}
alength := getLengths(headA)
blength := getLengths(headB)
for alength>blength{
headA = headA.Next
alength--
}
for blength>alength{
headB = headB.Next
blength--
}
for alength!=0{
if headA == headB{
return headA
}
headA = headA.Next
headB = headB.Next
alength--
}
return nil
}
func getLengths(head *ListNode) int {
res:=1
for head.Next!=nil{
res+= 1
head = head.Next
}
return res
}
时间:O(m+n) 空间:O(1)
双指针遍历两个链表,链表A长m,链表B长n,当指针遍历完一个链表后,重新指向另一个链表的头节点重新开始遍历
如果链表相交,当两个指针相同时,两个指针都刚好走过了 m + n
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null ){
return null;
}
ListNode pa = headA;
ListNode pb = headB;
while(pa != pb){
pa = pa == null? headB : pa.next;
pb = pb == null? headA : pb.next;
}
return pa;
}
}
时间复杂度遍历两个链表O(m + n)
空间复杂度使用两个指针O(1)
比较直接,遍历a全部放进哈希表,遍历b如果见到已经在哈希表中的则就是要找的节点,否则没有交点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA, headB):
a = headA
b = headB
if not a or not b:
return None
hash = {}
while a:
hash[a] = 1
a = a.next
while b:
if b in hash:
return b
else:
b = b.next
return None
heada交点前面长度是a,headb交点前面长度是b,相交的部分长度是c。那指针1走完a一整段再走b,指针b走完b一整段再走a,一定走的长度一样。如果两者不相交,在走完a+b+c之后也会在None处相等,所以循环的出口是指针1d的值==指针2的值
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA, headB):
a = headA
b = headB
while a != b:
if not a:
a = headB
else:
a = a.next
if not b:
b = headA
else:
b = b.next
return a
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
l1 = headA
l2 = headB
while l1 or l2:
if l1 == l2:
return l2
if l1:
l1 = l1.next
else:
l1 = headB
if l2:
l2 = l2.next
else:
l2 = headA
方法一:可以使用hash的方式,将其中一个链表的所有的值都存在hash中,再遍历另一链表,并判断其值是否再hash中。
方法二:使用双指针,同时遍历二个链表,当一个链表遍历完后,则接着另个链表进行遍历,当二个链表的指针相等的时候停止循环,(停止循环是有二种情况的,1是有重复的节点,2是未有重复节点,此时二个指针都指向的null)
public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { //方法一 使用hash\ // HashSet<ListNode> hash = new HashSet<>(); while(headA!=null){ hash.add(headA); headA = headA.next; } while(headB!=null){ if(hash.contains(headB))return headB; headB = headB.next; } return null; } } public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { //方法二 使用 双指针 ListNode first = headA; ListNode second = headB; while(first!=second){ if(first==null)first=headB; else first = first.next; if(second ==null)second = headA; else second = second.next; } return first; } }
时间复杂度:O(n)
空间复杂度:O(1) [方法1则是O(n)]
https://leetcode.com/problems/intersection-of-two-linked-lists/
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return null;
}
Set<ListNode> set = new HashSet<>();
ListNode pA = headA;
while(pA != null){
set.add(pA);
pA = pA.next;
}
ListNode pB = headB;
while(pB != null){
if(set.contains(pB)){
return pB;
}
pB = pB.next;
}
return null;
}
}
class Solution {
public:
//time f(n)=a+b+c=o(n) space o(1)
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
// 思路1 观察 链表倒序变量 ,如果不同就是上一个节点分开点。无法实现倒序遍历
// 思路2 直接2个指针 next移动。 根本不会相遇。 不一定对称结构
// 思路3:
/**为什么 a, b 指针相遇的点一定是相交的起始节点? 我们证明一下:
将两条链表按相交的起始节点继续截断,链表 1 为: A + C,链表 2 为: B + C;
当 a 指针将链表 1 遍历完后,重定位到链表 2 的头节点,然后继续遍历直至相交点,此时 a 指针遍历的距离为 A + C + B;
同理 b 指针遍历的距离为 B + C + A;**/
if (NULL == headA || NULL == headB )
{
return NULL;//不会相交
}
//前提:题目数据 保证 整个链式结构中不存在环。
ListNode* pa = headA;
ListNode* pb = headB;
//不是环形结构,缺打造一个环形结构。这里走一步 二步区分。
//A +B +C =C+B+A
while (pa != pb)
{
pa = pa ? pa->next:headB;
pb = pb ? pb->next:headA;
}
return pa;
}
};
class Solution {
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;
}
}
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return null;
}
ListNode pA = headA; ListNode pB = headB;
while(pA != pB){
pA = (pA == null) ? headB : pA.next;
pB = (pB == null) ? headA : pB.next;
}
return pA;
}
}
时间复杂度 O(n) 空间复杂度 O(1)
https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
使用cover
集合存储headA
中的每一个节点,然后遍历headB
,如果有节点在cover
中出现,则说明是相交节点,返回即可,如果没有在cover
中出现,说明不相交。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(headB == NULL || headA == NULL) return NULL;
ListNode* pa = headA;
unordered_set<ListNode*> cover;
while(pa != NULL)
{
cover.insert(pa);
pa = pa->next;
}
pa = headB;
while(pa != NULL)
{
if(cover.count(pa))
{
return pa;
}
pa = pa->next;
}
return NULL;
}
};
复杂度分析
O(M+N)
,M,N分别为headA
和headB
的长度O(M)
,M为headA
的长度先分别统计链表 A、B 的节点个数 countA,countB,长的那个先走 abs(countA - countB)步,然后两个链表一起走,直到相遇(返回相遇点)或有一个走完(返回null)
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 思路:先分别统计链表 A、B 的节点个数 countA,countB,长的那个先走 abs(countA - countB)步,然后两个链表一起走,直到相遇(返回相遇点)或有一个走完(返回null)
if (headA == null || headB == null)
return null;
int countA = 0, countB = 0;
ListNode currA = headA, currB = headB;
while (currA != null) {
countA++;
currA = currA.next;
}
while (currB != null) {
countB++;
currB = currB.next;
}
// 长的链表先走 diff 步
int diff = 0;
currA = headA;
currB = headB;
if (countA > countB) {
diff = countA - countB;
while (diff-- > 0) currA = currA.next;
} else {
diff = countB - countA;
while(diff-- > 0) currB = currB.next;
}
// 然后两个链表一起走,直至相遇
while (currA != null && currB != null) {
if (currA == currB)
return currA;
currA = currA.next;
currB = currB.next;
}
// 未找到相遇点
return null;
}
}
https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
List<ListNode> list = new ArrayList<>();
while (headA != null) {
list.add(headA);
headA = headA.next;
}
while (headB != null) {
if (list.contains(headB)) {
return headB;
}
headB = headB.next;
}
return null;
}
}
2 pointers, they first traverse their own list, then traverse each other's LinkedList. If they met, that's the intersection.
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null) return null;
ListNode a = headA;
ListNode b = headB;
while(a != b){
a = a == null ? headB : a.next;
b = b == null ? headA : b.next;
}
return a;
}
}
复杂度分析
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
a = headA
b = headB
while a != b:
a = a.next if a else headB
b = b.next if b else headA
# if 2 list never intersect, both will reach None at the end
if not a and not b: return None
return a
做过好几次,双指针指向两个头结点,指针指向null,换向另一个头结点,当两个指针相遇时,便是交点。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null|| headB == null){
return null;
}
ListNode tempA = headA;
ListNode tempB = headB;
while(tempA!=tempB){
tempA = tempA==null?headB:tempA.next;
tempB = tempB==null?headA:tempB.next;
}
return tempA;
}
}
时间复杂度O(m+n);
空间复杂度O(1);
0
[2,6,4]
[1,5]
3
2
note the termination status!
restart from the other head if reaches null
Time: O(lenA + lenB)
Space: O(1)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;
ListNode cur1 = headA, cur2 = headB;
while (cur1 != cur2) {
cur1 = cur1 == null ? headB : cur1.next;
cur2 = cur2 == null ? headA : cur2.next;
}
return cur1;
}
}
基于找之前出现过的元素的思路,选择了使用 hash 为基础的 set 来帮忙。 set 可以算这类问题的通用解法。但是没有利用到 linked list 本身的特性。
CPP
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
set<ListNode*> s;
if (headA == nullptr || headB == nullptr) return nullptr;
while (headA) {
s.insert(headA);
headA = headA->next;
}
while (headB) {
if (s.find(headB) != s.end()) return headB;
headB = headB->next;
}
return nullptr;
}
};
复杂度分析
var getIntersectionNode = function (headA, headB) {
if (!headA || !headB) return null;
let pA = headA,
pB = headB;
while (pA !== pB) {
pA = pA === null ? headB : pA.next;
pB = pB === null ? headA : pB.next;
}
return pA;
};
双指针
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
a, b = headA, headB
while a !=b:
a = a.next if a.next is not None else headB
b = b.next if b.next is not None else headA
return a
复杂度分析
public class Solution {
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;
}
}
时间复杂度O(m+n) 空间复杂度O(1)
利用哈希 Set 先遍历存储 A 的节点,再遍历 B 寻找 Set 中是否有一样的节点,若有则返回这个节点,否则返回 null
/**
* 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 set = new Set();
let temp = headA;
while(temp !== null) {
set.add(temp);
temp = temp.next;
}
temp = headB;
while(temp !== null) {
if(set.has(temp)) {
return temp;
}
temp = temp.next;
}
return null;
};
复杂度分析
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
na = 0
p1 = headA
while p1:
p1 = p1.next
na += 1
nb = 0
p2 = headB
while p2:
p2 = p2.next
nb += 1
# align the length of two linked lists
if na > nb:
diff = na - nb
while diff:
headA = headA.next
diff -= 1
else:
diff = nb - na
while diff:
headB = headB.next
diff -= 1
# start two pointers moving to the end
p1 = headA
p2 = headB
while (p1 is not None and p1!=p2):
p1 = p1.next
p2 = p2.next
return p1
time comp: O(M+N) space comp: O(1)
双指针问题,两个指针ab相同的速度向后移动,当 a 到达链表的尾部时,重定位到链表 B 的头结点当 b 到达链表的尾部时,重定位到链表 A 的头结点。两个指针相遇的点为相交的起始节点,否则没有相交点
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;
ListNode a = headA;
ListNode b = headB;
while (a != b) {
a = a == null ? headB : a.next;
b = b == null ? headA : b.next;
}
return a;
}
时间复杂度:O(N) 空间复杂度:O(1)
var getIntersectionNode = function (headA, headB) {
const visited = new Set()
let temp = headA
while (temp !== null) {
visited.add(temp)
temp = temp.next
}
temp = headB
while (temp !== null) {
if (visited.has(temp)) {
return temp
}
temp = temp.next
}
return null
}
利用双指针。指针a从headA出发一直遍历到tail,之后再放到headB往后遍历,指针b从headB出发一直遍历到tail,之后再放到headA往后遍历。如果有intersection,两个指针会在非tail的位置相遇,否则会都在tail(None)相遇。 证明:假设从headA到intersection距离为A,headB到intersection距离为B,从intersection到最后的距离为C(如果有intersection)。那么第二次到达intersection的时候指针a走的距离为A+C+B, 指针b走的距离为B+C+A
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
a = headA
b = headB
while a != b:
a = a.next if a else headB
b = b.next if b else headA
return a
"""
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
node_in_B = set()
while headB:
node_in_B.add(headB)
headB = headB.next
while headA:
if headA in node_in_B:
return headA
else:
headA = headA.next
return None
"""
TC: O(m+n)
SC: O(1)
思路 使用两个指针如指针 a, b 分别指向 A, B 这两条链表的头节点, 两个指针以相同的速度向后移动。 当 a 到达链表 A 的尾部时,将它重定位到链表 B 的头节点; 当 b 到达链表 B 的尾部时,将它重定位到链表 A 的头节点; 若在此过程中 a, b 指针相遇,则相遇节点为两链表相交的起始节点,否则说明两个链表不存在相交点。
ListNode getIntersectionNode(ListNode headA, ListNode *headB) { if (headA == NULL || headB == NULL) return NULL;
ListNode* pA = headA;
ListNode* pB = headB;
while (pA != pB) {
pA = pA == NULL ? headB : pA->next;
pB = pB == NULL ? headA : pB->next;
}
return pA;
}
时间复杂度:O(N) 空间复杂度:O(1)
官方答案不错,但比较难想出来。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// is A and B intersected?
int sizeA = 1;
ListNode tempA = headA;
int sizeB = 1;
ListNode tempB = headB;
while (tempA.next != null) {
sizeA++;
tempA = tempA.next;
}
while (tempB.next != null) {
sizeB++;
tempB = tempB.next;
}
// now, tempA and tempB is the end of each list
if (tempA != tempB) {
return null;
}
// if yes, then find the insection point
tempA = headA;
tempB = headB;
if (sizeA > sizeB) {
for (int i = 0; i < sizeA - sizeB; i++) {
tempA = tempA.next;
}
} else {
for (int i = 0; i < sizeB - sizeA; i++) {
tempB = tempB.next;
}
}
while (tempA != tempB) {
tempA = tempA.next;
tempB = tempB.next;
}
return tempA;
}
time comp: O(M+N) space comp: O(1)
单独遍历
let data = new Set();
while (A !== null) {
data.add(A);
A = A.next;
}
while (B !== null) {
if (data.has(B)) return B;
B = B.next;
}
return null;
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
'''
hashset = set()
pointA = headA
while pointA:
hashset.add(pointA)
pointA = pointA.next
pointB = headB
while pointB:
if pointB in hashset:
return pointB
else:
pointB = pointB.next
return None
'''
pointA, pointB = headA, headB
while pointA != pointB:
if pointA == pointB == None:
return None
if pointA == None:
pointA = headB
else:
pointA = pointA.next
if pointB == None:
pointB = headA
else:
pointB = pointB.next
return pointA
Hashset method: Time complexity O(n) Space complexity O(n) Two pointers method: Time complexity O(n) Space complexity O(1)
双指针
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
A, B = headA, headB
while A != B:
if A:
A = A.next
else:
A = headB
if B:
B = B.next
else:
B = headA
return A
复杂度分析
通过哈系表存储A的节点,然后遍历B,判断nodeA是否等于nodeB
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
stack = set()
while(headA):
stack.add(headA)
headA = headA.next
while(headB):
if headB in stack:
return headB
else:
headB = headB.next
return None
复杂度分析
var getIntersectionNode = function(headA, headB) {
if (headA === null || headB === null) return null;
let pA = headA, pB = headB;
while (pA !== pB) {
pA = pA === null ? headB : pA.next; //链表A循环结束就循环链表B
pB = pB === null ? headA : pB.next; //链表A循环结束就循环链表B
}
return pA; //当pA == pB时就是交点
};
时间复杂度O(m+n),m、n分别是两个链表的长度。空间复杂度O(1)
遍历lista,把节点都push到数组里存起来,然后遍历listb,判断数组里是否存在相同节点,有的话就说明这个就是重合的起始点
var getIntersectionNode = function(headA, headB) {
let p = headA;
let arr = [];
while(p) {
arr.push(p);
p = p.next;
}
let q = headB;
while(q){
if(arr.includes(q)) {
return q;
} else {
q = q.next;
}
}
return null;
};
时间复杂度:O(m+n) 空间复杂度:O(m)
C++ Code:
/**
* 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) {
// we can use map. or use switching method.
ListNode* list1 = headA;
ListNode* list2 = headB;
while(list1!=list2)
{
if(list1 == NULL)
list1 = headB;
else
list1 = list1->next;
if(list2 == NULL)
{
list2 = headA;
}
else
list2 = list2->next;
}
return list1;
}
};
public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if(headA==null || headB==null){ return null; } ListNode p1=headA ,p2=headB; while(p1 != p2){ p1 = p1==null ? headB : p1.next; p2 = p2==null ? headA : p2.next; } return p1; } }
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
a = headA
b = headB
while a != b:
if a:
a = a.next
else:
a = headB
if b:
b = b.next
else:
b = headA
return a
时间复杂度:O(N)
空间复杂度:O(1)
思路:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> set = new HashSet();
while(headA!=null){
set.add(headA);
headA = headA.next;
}
while(headB!=null){
if(set.contains(headB)){
return headB;
}
headB = headB.next;
}
return null;
}
}
时间: O(m+n);m为链表A长度,n为链表B长度.
空间:O(m);m为链表A长度.
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if not headA or not headB:
return None
a, b = headA, headB
while(a and b):
if a == b:
return a
if not a.next and not b.next:
return None
a = a.next if a.next else headB
b = b.next if b.next else headA
return None
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//双指针,indexA,indexB一起出发,indexA走到头后就从B出发,indexB走到头后再从A出发
//两个指针最终的交点就是结果
ListNode indexA = headA;
ListNode indexB = headB;
boolean isFirstTimeA = true;
boolean isFirstTimeB = true;
while(indexA != null && indexB != null && indexA != indexB){
indexA = indexA.next;
indexB = indexB.next;
if(indexA == null && isFirstTimeA){
indexA = headB;
isFirstTimeA = false;
}
if(indexB == null && isFirstTimeB){
indexB = headA;
isFirstTimeB = false;
}
}
return indexA == indexB ? indexA : null;
}
}
时间复杂度:$O(n)$
空间复杂度:$O(1)$
思路一写麻烦了,如果两个链表没有相交,那么他们最后会同时为null!!
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//双指针,indexA,indexB一起出发,indexA走到头后就从B出发,indexB走到头后再从A出发
//两个指针最终的交点就是结果
ListNode indexA = headA;
ListNode indexB = headB;
while(indexA != indexB){
indexA = indexA != null ? indexA.next : headB;
indexB = indexB != null ? indexB.next : headA;
}
return indexA;
}
}
时间复杂度:$O(n)$
空间复杂度:$O(1)$
长的链表提前遍历n次,然后两个链表同时遍历,判断节点是否相等
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
dummyA, dummyB = headA, headB
n1 = 0
while dummyA:
n1 += 1
dummyA = dummyA.next
n2 = 0
while dummyB:
n2 += 1
dummyB = dummyB.next
if n1 > n2:
n = n1 - n2
while n:
headA = headA.next
n -= 1
if n2 > n1:
n = n2 - n1
while n:
headB = headB.next
n -= 1
while headA:
if headA is headB:
return headA
headA = headA.next
headB = headB.next
return None
class Solution: def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: if headA is None or headB is None: return null pointA = headA pointB = headB while pointA != pointB: if pointA is None: pointA = headB else: pointA = pointA.next if pointB is None: pointB = headA else: pointB = pointB.next return pointB
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode A = headA;
ListNode B = headB;
while(A!=B){
A = A==null?headB:A.next;
B = B== null?headA:B.next;
}
return A;
}
}
/**
/**
https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
自定义评测:
评测系统 的输入如下(你设计的程序 不适用 此输入):
intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
listA - 第一个链表
listB - 第二个链表
skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数
评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。
提示:
listA 中节点数目为 m
listB 中节点数目为 n
1 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
如果 listA 和 listB 没有交点,intersectVal 为 0
如果 listA 和 listB 有交点,intersectVal == listA[skipA] == listB[skipB]
进阶:你能否设计一个时间复杂度 O(m + n) 、仅用 O(1) 内存的解决方案?
Java Code:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null ||headB == null){
return null;
}
ListNode p1 = headA;
ListNode p2 = headB;
//如果两个链表没有节点,如果链表长度相同则headA,headB最终同时指向null,只有一个指针为空,问题不大
while (headA !=headB){
headA = headA == null ? p2: headA.next;
headB = headB == null ? p1: headB.next;
}
return headA;
}
}
复杂度分析
令 n ,m为链表长度。
哈希表法
这个题目本质上是要找相同的元素,自然而然的可以想到用哈希表
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
return hashSetSolution(headA,headB);
}
/**
* 这个题目本质上是要找相同的元素,自然而然的可以想到用哈希表
*
* 时间复杂度:O(m+n),其中 m 和 n 是分别是链表 headA 和 headB 的长度。需要遍历两个链表各一次。
* 空间复杂度:O(m),其中 m 是链表 headA 的长度。需要使用哈希集合存储链表 headA 中的全部节点。
*
* @param headA
* @param headB
* @return
*/
private ListNode hashSetSolution(ListNode headA, ListNode headB){
// 题目要求的是 Node 的地址相同,而不是 val 相同,
// 所以 Set 里存的应该是 ListNode
Set<ListNode> hashSet = new HashSet<>();
ListNode tmp = headA;
while (tmp != null){
hashSet.add(tmp);
tmp = tmp.next;
}
tmp = headB;
while (tmp != null){
if (hashSet.contains(tmp)){
return tmp;
}
tmp = tmp.next;
}
return null;
}
分别做两个指针,从开头开始走,如果到一边的结尾则去另一边的开头
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode a=headA;
ListNode b=headB;
int check=0;
while(a!=b)
{
if (a.next==null)
{
if(check==2)
{return null;}
check+=1;
a=headB;
}
else
{
a=a.next;
}
if (b.next==null)
{
if(check==2)
{return null;}
check+=1;
b=headA;
}
else
{
b=b.next;
}
}
return a;
}
}
双指针,分别遍历两个链表,到链表末尾的时候,连接到另外一个链表,相当于相同的速度,一样的路程,如果相遇,就是第一个相遇的点
var getIntersectionNode = function(headA, headB) {
if (headA == null || headB == null) {
return null;
}
let pA = headA;
let pB = headB;
while (pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
};
时间复杂度:O(m+n) m,n分别为两个链表的长度
空间复杂度:O(1)
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
nodes_B = set()
while headB:
nodes_B.add(headB)
headB = headB.next
while headA:
if headA in nodes_B:
return headA
headA = headA.next
return None
https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
最坏情况会遍历完两个链表,时间复杂度O(m+n)
160. 相交链表
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
前置知识
题目描述
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 输出:Intersected at '8' 解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。 在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Intersected at '2' 解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。 示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 输出:null 解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。 由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 这两个链表不相交,因此返回 null 。
提示:
listA 中节点数目为 m listB 中节点数目为 n 0 <= m, n <= 3 * 104 1 <= Node.val <= 105 0 <= skipA <= m 0 <= skipB <= n 如果 listA 和 listB 没有交点,intersectVal 为 0 如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]
进阶:你能否设计一个时间复杂度 O(n) 、仅用 O(1) 内存的解决方案?