leetcode-master/problems/面试题02.07.链表相交.md

409 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 面试题 02.07. 链表相交
160.链表相交
[力扣题目链接](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/)
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211219221657.png)
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211219221723.png)
示例 2
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211219221749.png)
示例 3
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211219221812.png)![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211219221812.png)
## 思路
简单来说,就是求两个链表交点节点的**指针**。 这里同学们要注意,交点不是数值相等,而是指针相等。
为了方便举例,假设节点元素数值相等,则节点指针相等。
看如下两个链表目前curA指向链表A的头结点curB指向链表B的头结点
![面试题02.07.链表相交_1](https://code-thinking.cdn.bcebos.com/pics/面试题02.07.链表相交_1.png)
我们求出两个链表的长度并求出两个链表长度的差值然后让curA移动到和curB 末尾对齐的位置,如图:
![面试题02.07.链表相交_2](https://code-thinking.cdn.bcebos.com/pics/面试题02.07.链表相交_2.png)
此时我们就可以比较curA和curB是否相同如果不相同同时向后移动curA和curB如果遇到curA == curB则找到交点。
否则循环退出返回空指针。
C++代码如下:
```CPP
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上末尾位置对齐
while (gap--) {
curA = curA->next;
}
// 遍历curA 和 curB遇到相同则直接返回
while (curA != NULL) {
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
```
* 时间复杂度O(n + m)
* 空间复杂度O(1)
## 其他语言版本
### Java
```Java
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0, lenB = 0;
while (curA != null) { // 求链表A的长度
lenA++;
curA = curA.next;
}
while (curB != null) { // 求链表B的长度
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头lenA为其长度
if (lenB > lenA) {
//1. swap (lenA, lenB);
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
//2. swap (curA, curB);
ListNode tmpNode = curA;
curA = curB;
curB = tmpNode;
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上末尾位置对齐
while (gap-- > 0) {
curA = curA.next;
}
// 遍历curA 和 curB遇到相同则直接返回
while (curA != null) {
if (curA == curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
```
### Python
```python
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA, lenB = 0, 0
cur = headA
while cur: # 求链表A的长度
cur = cur.next
lenA += 1
cur = headB
while cur: # 求链表B的长度
cur = cur.next
lenB += 1
curA, curB = headA, headB
if lenA > lenB: # 让curB为最长链表的头lenB为其长度
curA, curB = curB, curA
lenA, lenB = lenB, lenA
for _ in range(lenB - lenA): # 让curA和curB在同一起点上末尾位置对齐
curB = curB.next
while curA: # 遍历curA 和 curB遇到相同则直接返回
if curA == curB:
return curA
else:
curA = curA.next
curB = curB.next
return None
```
### Go
```go
func getIntersectionNode(headA, headB *ListNode) *ListNode {
curA := headA
curB := headB
lenA, lenB := 0, 0
// 求AB的长度
for curA != nil {
curA = curA.Next
lenA++
}
for curB != nil {
curB = curB.Next
lenB++
}
var step int
var fast, slow *ListNode
// 请求长度差,并且让更长的链表先走相差的长度
if lenA > lenB {
step = lenA - lenB
fast, slow = headA, headB
} else {
step = lenB - lenA
fast, slow = headB, headA
}
for i:=0; i < step; i++ {
fast = fast.Next
}
// 遍历两个链表遇到相同则跳出遍历
for fast != slow {
fast = fast.Next
slow = slow.Next
}
return fast
}
```
双指针
```go
func getIntersectionNode(headA, headB *ListNode) *ListNode {
l1,l2 := headA, headB
for l1 != l2 {
if l1 != nil {
l1 = l1.Next
} else {
l1 = headB
}
if l2 != nil {
l2 = l2.Next
} else {
l2 = headA
}
}
return l1
}
```
### javaScript
```js
var getListLen = function(head) {
let len = 0, cur = head;
while(cur) {
len++;
cur = cur.next;
}
return len;
}
var getIntersectionNode = function(headA, headB) {
let curA = headA,curB = headB,
lenA = getListLen(headA), // 求链表A的长度
lenB = getListLen(headB);
if(lenA < lenB) { // 让curA为最长链表的头lenA为其长度
// 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
// 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
[curA, curB] = [curB, curA];
[lenA, lenB] = [lenB, lenA];
}
let i = lenA - lenB; // 求长度差
while(i-- > 0) { // 让curA和curB在同一起点上末尾位置对齐
curA = curA.next;
}
while(curA && curA !== curB) { // 遍历curA 和 curB遇到相同则直接返回
curA = curA.next;
curB = curB.next;
}
return curA;
};
```
TypeScript
```typescript
function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
let sizeA: number = 0,
sizeB: number = 0;
let curA: ListNode | null = headA,
curB: ListNode | null = headB;
while (curA) {
sizeA++;
curA = curA.next;
}
while (curB) {
sizeB++;
curB = curB.next;
}
curA = headA;
curB = headB;
if (sizeA < sizeB) {
[sizeA, sizeB] = [sizeB, sizeA];
[curA, curB] = [curB, curA];
}
let gap = sizeA - sizeB;
while (gap-- && curA) {
curA = curA.next;
}
while (curA && curB) {
if (curA === curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
};
```
C
```c
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *l = NULL, *s = NULL;
int lenA = 0, lenB = 0, gap = 0;
// 求出两个链表的长度
s = headA;
while (s) {
lenA ++;
s = s->next;
}
s = headB;
while (s) {
lenB ++;
s = s->next;
}
// 求出两个链表长度差
if (lenA > lenB) {
l = headA, s = headB;
gap = lenA - lenB;
} else {
l = headB, s = headA;
gap = lenB - lenA;
}
// 尾部对齐
while (gap--) l = l->next;
// 移动,并检查是否有相同的元素
while (l) {
if (l == s) return l;
l = l->next, s = s->next;
}
return NULL;
}
```
Scala:
```scala
object Solution {
def getIntersectionNode(headA: ListNode, headB: ListNode): ListNode = {
var lenA = 0 // headA链表的长度
var lenB = 0 // headB链表的长度
var tmp = headA // 临时变量
// 统计headA的长度
while (tmp != null) {
lenA += 1;
tmp = tmp.next
}
// 统计headB的长度
tmp = headB // 临时变量赋值给headB
while (tmp != null) {
lenB += 1
tmp = tmp.next
}
// 因为传递过来的参数是不可变量,所以需要重新定义
var listA = headA
var listB = headB
// 两个链表的长度差
// 如果gap>0lenA>lenBheadA(listA)链表往前移动gap步
// 如果gap<0lenA<lenBheadB(listB)链表往前移动-gap步
var gap = lenA - lenB
if (gap > 0) {
// 因为不可以i-=1所以可以使用for
for (i <- 0 until gap) {
listA = listA.next // 链表headA(listA) 移动
}
} else {
gap = math.abs(gap) // 此刻gap为负值取绝对值
for (i <- 0 until gap) {
listB = listB.next
}
}
// 现在两个链表同时往前走,如果相等则返回
while (listA != null && listB != null) {
if (listA == listB) {
return listA
}
listA = listA.next
listB = listB.next
}
// 如果链表没有相交则返回nullreturn可以省略
null
}
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>