题目描述
输入两个无环的单链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
题解
公共节点:两个链表从某一节点开始,他们的next都指向同一个节点。但由于是单向链表的节点,每个节点只有一个next,因此从第一个公共节点开始,之后他们的所有节点都是重合的,不可能再出现分叉。
下图中第一个公共结点为8。
方法一:双指针 + 单循环 (遍历两遍这两个链表)
思路:遍历两遍这两个链表,如果有重复的节点,那么一定能够使遍历的指针相等。
遍历两遍这两个链表,相当于连接两个链表,使两个指针遍历的长度相等,遇到第一个相同的节点返回即可。如果2个相加的链表,表头不相等 则肯定有共同尾部。
有以下两种情况:
- 如果两链表长度相等, 那么只需遍历一遍,就可以得到公共结点。
- 如果两链表长度不相等, 那么只遍历一遍数组,两指针总会错开的。 如下图所示:
解决两链表长度不相等:
如果A指针把链表A走完了,然后再从链表B开始走到相遇点,就相当于把这两个链表的所有节点都走了一遍。B指针同理。
- 如果只要这两个链表相交(有公共节点),最终肯定会在相交点相遇;
- 如果不相交(没有有公共节点),最终他们都会同时走到两个链表的末尾。
步骤:
- 创建两个指针 node1 和 node2,分别指向两个链表的头结点,然后依次往后遍历。
- 如果某个指针到达末尾,则将该指针指向另一个链表的头结点;
- 如果两个指针所指的节点相同,则循环结束,返回当前指针指向的节点。
复杂度分析:
- 时间复杂度:O(m+n)
m,n分别为链表A,B的长度,最坏情况下,公共结点为最后一个,需要遍历m+n个结点 - 空间复杂度:O(1)
C#:
public class ListNode
{
public int val;
public ListNode next;
public ListNode (int x)
{
val = x;
}
}
class Solution
{
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2)
{
if(pHead1 == null || pHead2 == null)
{
return null;
}
ListNode node1 = pHead1;
ListNode node2 = pHead2;
while (node1!=node2)
{
if (node1 != null)
{
node1 = node1.next;
}
if (node2 != null)
{
node2 = node2.next;
}
if (node1!=node2)
{
if (node1 == null)
{
node1 = pHead2;
}
if (node2 == null)
{
node2 = pHead1;
}
}
}
return node1;
}
}
利用三元运算符优化上面代码:
public class ListNode
{
public int val;
public ListNode next;
public ListNode (int x)
{
val = x;
}
}
class Solution
{
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2)
{
if(pHead1 == null || pHead2 == null)
{
return null;
}
ListNode node1=pHead1;
ListNode node2=pHead2;
while(node1!=node2)
{
node1 = (node1 == null ? pHead2:node1.next);
node2 = (node2 == null ? pHead1:node2.next);
}
return node1;
}
}
方法二:双指针 + 双循环 (暴力破解法)
思路:
- 遍历链表A,指针 node1 指向A链表的头结点;
- 遍历链表B,将链表B的结点逐一与 node1 比较。
如果是公共结点,则返回该结点;
如果没有公共结点,node1 = node1.next,再与链表B的结点逐一比较 - node1 == null,则返回null。
复杂度分析:
- 时间复杂度:O(mn)
m,n分别为链表A,B的长度,最坏情况下,公共结点为最后一个,需要遍历m*n个结点 - 空间复杂度:O(1)
C#
public class ListNode
{
public int val;
public ListNode next;
public ListNode (int x)
{
val = x;
}
}
class Solution
{
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2)
{
ListNode node1 = pHead1;
while (node1 != null)
{
ListNode node2 = pHead2;
while (node2 != null)
{
if (node1 == node2)
return node1;
node2 = node2.next;
}
node1 = node1.next;
}
return null;
}
}