题目:输入两个链表,找出它们的第一个公共结点。链表的结点定义如下:
//链表结点
struct ListNode {
int m_nKey;
ListNode* m_pNext;
};
思路1:将两个链表中的结点分别压入两个栈中,然后判断两栈栈顶的下一个结点(指针)是否相同,如果相同记录这个结点并将两栈出栈,直到两栈顶的下一个结点指向两个不同的结点,返回记录结点。
//求两个链表的第一个公共结点——借助栈
ListNode* firstCommonNodeWithStack(ListNode* head1, ListNode* head2) {
if (NULL == head1 || NULL == head2) {
return NULL;
}
ListNode* p = head1->m_pNext;
ListNode* q = head2->m_pNext;
std::stack<ListNode*> stack1;
std::stack<ListNode*> stack2;
while (p != NULL || q != NULL) {
//将这两个链表的所有非空结点从头至尾入栈
if (p != NULL) {
stack1.push(p);
p = p->m_pNext;
}
if (q != NULL) {
stack2.push(q);
q = q->m_pNext;
}
}
//倒序遍历时,指向两个链表中的第一公共结点
ListNode* pCommonNode = NULL;
while (!stack1.empty() && !stack2.empty()) {
//两栈同时出栈并查看其是否指向同一结点
p = stack1.top();
q = stack2.top();
if (p->m_pNext == q->m_pNext) {
//保存最前面的公共结点
pCommonNode = p->m_pNext;
stack1.pop();
stack2.pop();
} else {
break;
}
}
return pCommonNode;
}
思路2:先求出两个链表的长度并求出两个链表的长度差的绝对值diff,先遍历较长链表diff个结点,然后同时遍历两个链表,比较两个链表的结点是相交。
//求两个链表的第一个公共结点——先走几步(短链表是长链表的子链表的情况————没有考虑)
ListNode* firstCommonNode(ListNode* head1, ListNode* head2) {
if (NULL == head1 || NULL == head2) {
return NULL;
}
//计数器,分别记录两个链表的长度
int length1 = 0, length2 = 0;
ListNode* p = head1->m_pNext, *q = head2->m_pNext;
while (NULL != p || NULL != q) {
if (NULL != p) {
++length1;
p = p->m_pNext;
}
if (NULL != q) {
++length2;
q = q->m_pNext;
}
}
//计算两个链表的长度差
int difference = std::abs(length1 - length2);
//r:相对较长的那个链表第一个结点,s:相对较短的那个链表第一个结点
ListNode* r = NULL, *s = NULL;
if (length1 >= length2) {
r = head1->m_pNext;
s = head2->m_pNext;
} else {
r = head2->m_pNext;
s = head1->m_pNext;
}
while (difference > 0) {
r = r->m_pNext;
--difference;
}
while (r != NULL && s != NULL) {
if (r->m_pNext != s->m_pNext) {
r = r->m_pNext;
s = s->m_pNext;
} else {
return r->m_pNext;
}
}
return NULL;
}
测试代码
/*
*
* Created on: 2014-4-25 11:45:08
* Author: danDingCongRong
*/
#include<iostream>
using namespace std;
//创建链表
ListNode* createList(int length) {
//创建表头结点
ListNode* head = new ListNode();
head->m_pNext = NULL;
ListNode* p = head;
int value = 0; //临时存储用户键入的第i个结点值
for (int i = 0; i < length; ++i) {
cout << "ListNode" << i << ":\t";
cin >> value;
//将新创建的结点插入链表中
ListNode* q = new ListNode();
q->m_nKey = value;
q->m_pNext = NULL;
p->m_pNext = q;
p = q;
}
return head;
}
//创建两个链表
void createDoubleList(ListNode* head1, ListNode* head2, int difference) {
if (NULL == head1 || NULL == head2 || 0 >= difference) {
return;
}
//找到第一个链表的第difference个结点
ListNode* p = head1->m_pNext;
for (int i = 0; i < difference; ++i) {
if (NULL != p) {
p = p->m_pNext;
} else {
return;
}
}
//将第二个链表的末尾结点指向第一个链表的第difference个结点
ListNode* q = head2;
while (q->m_pNext != NULL) {
q = q->m_pNext;
}
q->m_pNext = p;
}
//遍历输出链表(从表头到表尾)
void showList(ListNode* head) {
//如果是空链表直接退出
if (NULL == head)
return;
ListNode* p = head->m_pNext;
while (p != NULL) {
cout << p->m_nKey << "\t";
p = p->m_pNext;
}
cout << endl;
}
int main() {
int length1 = 0, length2 = 0, difference = 0;
cout << "输入两个链表的长度和插入位置:" << endl;
while (cin >> length1 >> length2 >> difference) {
ListNode* head1 = createList(length1);
cout << "原始链表1:" << endl;
showList(head1);
ListNode* head2 = createList(length2);
cout << "原始链表2:" << endl;
showList(head2);
createDoubleList(head1, head2, difference);
ListNode* result1 = firstCommonNodeWithStack(head1, head2);
if (NULL == result1) {
cout << "result1=NULL" << endl;
} else {
cout << "result1=" << result1->m_nKey << endl;
}
ListNode* result2 = firstCommonNode(head1, head2);
if (NULL == result2) {
cout << "result2=NULL" << endl;
} else {
cout << "result2=" << result2->m_nKey << endl;
}
cout << "输入两个链表的长度和插入位置:" << endl;
}
return 0;
}
注:部分内容参考自剑指offer