剑指 Offer 52. 两个链表的第一个公共节点
Posted 是七喜呀!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 52. 两个链表的第一个公共节点相关的知识,希望对你有一定的参考价值。
题目链接: 剑指 Offer 52. 两个链表的第一个公共节点
有关题目
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
题解
方法一:暴力法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
for (struct ListNode* pa = headA; pa != NULL; pa = pa->next)
for(struct ListNode* pb = headB; pb != NULL; pb = pb->next)
if (pa == pb) return pa;
return NULL;
}
方法二:哈希集合
思路:
使用哈希集合,遍历链表A,同时存放链表A中的节点
然后遍历B,判断两者是否右公共节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct HashTable {
struct ListNode *key;
UT_hash_handle hh;
};//哈希表存储链表节点
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct HashTable *hashTable = NULL;
struct ListNode *temp = headA;//拷贝链表A
while (temp != NULL)
{
struct HashTable *tmp;
//在hashTable中找temp,返回tmp;
HASH_FIND(hh, hashTable, &temp, sizeof(struct HashTable *), tmp);
if (tmp == NULL)
{
tmp = malloc(sizeof(struct HashTable));
tmp->key = temp;
//把tmp中的key值添加到hashTable中
HASH_ADD(hh, hashTable, key, sizeof(struct HashTable *), tmp);
}
temp = temp->next;//指向下一个节点
}
//遍历链表B
temp = headB;//拷贝链表B
while (temp != NULL)
{
struct HashTable *tmp;
HASH_FIND(hh, hashTable, &temp, sizeof(struct HashTable *), tmp);
if (tmp != NULL)
return temp;
temp = temp->next;
}
return NULL;
}
方法三:栈解法
思路:
从后往前找,将两条链表分别压入两个栈中,然后循环比较两个栈的栈顶元素,同时记录上一位栈顶元素。
当遇到第一个不同的节点时,结束循环,上一位栈顶元素即是答案。
public class Solution {
public ListNode getIntersectionNode(ListNode a, ListNode b) {
Deque<ListNode> d1 = new ArrayDeque<>(), d2 = new ArrayDeque<>();
while (a != null) {
d1.add(a);
a = a.next;
}
while (b != null) {
d2.add(b);
b = b.next;
}
ListNode ans = null;
while (!d1.isEmpty() && !d2.isEmpty() && d1.peekLast() == d2.peekLast()) {
//peekLast返回最后一个对象或元素
ans = d1.pollLast();
//pollLast检索链表的最后一个元素或结尾元素,返回最后一个对象,最后从列表中删除最后一个元素
//列表为空,则它将返回null
d2.pollLast();
}
return ans;
}
}
方法四:双指针
代码一:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if (headA == NULL || headB == NULL)
return NULL;
struct ListNode *pA = headA, *pB = headB;
int lenA = 0, lenB = 0;//链表A,B的长度
//计算A的长度
while(pA != NULL)
{
lenA++;
pA = pA -> next;
}
//计算B的长度
while(pB != NULL)
{
lenB++;
pB = pB -> next;
}
//比较两者长度差
int diff = lenA -lenB;
//链表A比B长,或相等
if (diff >= 0)
{
pA = headA;
//因为A比B长diff,所以A先走diff步
for (int i = 0; i < diff; i++)
pA = pA -> next;
pB = headB;
//然后A,B一起走,相遇时说明找到了第一个相交的结点
while(pA != NULL)
{
if (pA == pB)
return pA;
pA = pA -> next;
pB = pB -> next;
}
}
else
{
pB = headB;
//因为A比B短diff,所以B先走负diff步
for (int i = 0; i < 0 - diff; i++)
pB = pB -> next;
pA = headA;
while(pA != NULL)
{
if (pA == pB)
return pA;
pA = pA -> next;
pB = pB -> next;
}
}
//执行到这里说明A,B不相交,返回NULL
return NULL;
}
代码一简化版:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if (headA == NULL || headB == NULL)
return NULL;
struct ListNode *pA = headA, *pB = headB;
int lenA = 0, lenB = 0;//链表A,B的长度
//计算A的长度
while(pA != NULL && lenA++ >= 0) pA = pA -> next;
//计算B的长度
while(pB != NULL && lenB++ >= 0) pB = pB -> next;
//比较两者长度差
int diff = lenA -lenB;
pA = headA;
pB = headB;//重置
//链表A比B长,或相等
if (diff >= 0)
{
//因为A比B长diff,所以A先走diff步
for (int i = 0; i < diff; i++)
pA = pA -> next;
}
else if (diff < 0)
{
//因为A比B短diff,所以B先走负diff步
for (int i = 0; i < 0 - diff; i++)
pB = pB -> next;
}
//然后A,B一起走,相遇时说明找到了第一个相交的结点
while(pA != NULL)
{
if (pA == pB)
return pA;
pA = pA -> next;
pB = pB -> next;
}
return NULL;
}
代码二:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if (headA == NULL || headB == NULL)
return NULL;
struct ListNode *pA = headA, *pB = headB;//双指针pA,pB
while (pA != pB)
{
pA = pA == NULL ? headB : pA->next;
pB = pB == NULL ? headA : pB->next;
}
return pA;
}
以上是关于剑指 Offer 52. 两个链表的第一个公共节点的主要内容,如果未能解决你的问题,请参考以下文章