开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 16 天,点击查看活动详情
Day44 2023/02/19
难度:简单
题目
示例1
输入:str1 = {l, o, a, d, i, n, g}; str2 = {b, e, i, n, g}
输出:节点i
思路
本题若直接从头遍历两个链表并比较节点的话是不可行的,因为两个链表的长度不一定相同,若一长一短的话,则较长的链表存在节点无法与较短链表进行比较,导致错过公共节点,所以一开始我们要对齐两个链表,如图所示:
为什么可以这样直接对齐,是由于两个链表从第一个公共结点到链表的尾结点都是重合的,所以公共节点一定不会在长链表与短链表对齐之外的部分。
具体步骤:
- 分别求出 str1 和 str2 所指的两个链表的长度 m 和 n 。
- 将两个链表以表尾对齐:令指针 p 、 q 分别指向 str1 和 str2 的头结点,若 m>=n ,则使 p 指向链表中的第 m-n+1 个结点;若 m<n ,则使 q 指向链表中的第 n-m+1 个结点,即使指针 p 和 q 所指的结点到表尾的长度相等。
- 指针 p 和 q 同步向后移动,并判断它们是否指向同一结点。若 p 和 q 指向同一结点,则该点即为所求的共同后缀的起始位置。
关键点
- 这里的公共节点不是指节点的数据域相同,而是指它们未同一个节点。
算法实现
#include <iostream>
using namespace std;
// 定义单链表
struct LNode {
int val; // 数据域
LNode* next; // 指针域
LNode(int x) : val(x), next(nullptr){}; // 构造函数
};
class Solution {
public:
LNode* FindCommonNode(LNode* str1, LNode* str2) {
int m = GetLengthOfLink(str1);
int n = GetLengthOfLink(str2);
int time = 0; // 对齐次数
// 对齐两链表
if (m >= n) {
time = m - n + 1;
while(time--) str1 = str1->next;
}else {
time = n - m + 1;
while (time--) str2 = str2->next;
}
// 同时出发遍历,比较节点,若相同就返回,否则没有公共节点
while (str1 && str2) {
if(str1 == str2) return str1; // 注意是节点相同
}
return nullptr;
}
private:
// 获取链表长度
int GetLengthOfLink(LNode* link) {
int length = 0;
while(link) {
link = link->next;
length++;
}
return length;
}
};
c++代码实现
- 时间复杂度 --- 最坏情况下p ,q一共访问了2n个节点,其中n为较短链表的长度
- 空间复杂度 --- 两个链表为必要空间,除此无额外的辅助空间
总结
- 这里一定要理解公共节点是指为同一个节点,而不是单纯的数据域相同,不然不太好理解为什么可以这样对齐。