板子:两个链表的公共结点(2012)
两条链表从第一个公共结点开始,后面的结点全部共用,形状像字母 Y。所以公共部分一定在尾部:先让长的那条多走
步,把两边剩下的长度对齐,再一起往后走,第一次指向同一个结点的地方就是答案。
代码
int listLen(LinkList L) { // 表长,不算头结点
int n = 0;
for (LNode *p = L->next; p != NULL; p = p->next) n++;
return n;
}
LNode *findCommon(LinkList str1, LinkList str2) { // 2012:共同后缀的起始结点
int m = listLen(str1), n = listLen(str2);
LNode *p = str1, *q = str2;
for (; m > n; m--) p = p->next; // 长的那条先走 |m-n| 步,之后两边剩下的一样长
for (; n > m; n--) q = q->next; // 两个 for 只会有一个真正执行
while (p != q) { // 比较的是地址:公共结点是同一个结点,不只是值相等
p = p->next;
q = q->next;
}
return p; // 没有公共结点时两边同时走到 NULL,返回 NULL
}复杂度:时间
例(2012 原题):loading 和 being 共用后缀 ing,返回的是 i 那个结点。
易错点
- 比较的是
p != q(地址),不是p->data != q->data。两个单词里各有一个i,但它们不一定是同一个结点。 - 两条链表不可能交叉成 X 形:一个结点只有一个
next,一旦汇合就不会再分开。 - 暴力解是对
str1的每个结点都把str2扫一遍,,也是正确解。 - 求表长不算头结点,两边口径一样就行,对齐的步数不受影响。