题目来源: JZ52 两个链表的第一个公共结点
题目描述:
- 描述: 输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的) 数据范围: n≤1000
- 要求: 空间复杂度 O(1),时间复杂度 O(n)
- 例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:
- 可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。
- 例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:
- 输入描述: 输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。
- 返回值描述: 返回传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表。
示例1:
输入:{1,2,3},{4,5},{6,7}
返回值:{6,7}
说明: 第一个参数{1,2,3}代表是第一个链表非公共部分,第二个参数{4,5}代表是第二个链表非公共部分,最后的
{6,7}表示的是2个链表的公共部分。
这3个参数最后在后台会组装成为2个两个无环的单链表,且是有公共节点的
示例2:
输入:{1},{2,3},{}
输出:{}
说明:2个链表没有公共节点 ,返回null,后台打印{}
思路1:
- 1.使用两个指针N1,N2,一个从链表1的头节点开始遍历,我们记为N1,一个从链表2的头节点开始遍历,我们记为N2。
- 2.让N1和N2一起遍历,当N1先走完链表1的尽头(为null)的时候,则从链表2的头节点继续遍历
- 3.同样,如果N2先走完了链表2的尽头,则从链表1的头节点继续遍历,也就是说,N1和N2都会遍历链表1和链表2。
- 4.因为两个指针,同样的速度,走完同样长度(链表1+链表2),不管两条链表有无相同节点,都能够到达同时到达终点。(N1最后肯定能到达链表2的终点,N2肯定能到达链表1的终点)。
- 5.得到公共节点:
- 有公共节点的时候,N1和N2必会相遇,因为长度一样嘛,速度也一定,必会走到相同的地方的,所以当两者相等的时候,则会第一个公共的节点
- 无公共节点的时候,此时N1和N2则都会走到终点,那么他们此时都是null,所以也算是相等了。
具体实现1:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode l1 = pHead1, l2 = pHead2;
while(l1 != l2){
l1 = (l1==null)?pHead2:l1.next;
l2 = (l2==null)?pHead1:l2.next;
}
return l1;
}
}
- 复杂度分析:
- 时间复杂度O(m+n):链表1和链表2的长度之和。
- 空间复杂度O(1):常数的空间。
思路2:枚举
逐个检查哪个节点相同
具体实现2:
public class Solution {
public ListNode FindFirstCommonNode(ListNode a, ListNode b) {
for (ListNode h1 = a; h1 != null ; h1 = h1.next) {
for (ListNode h2 = b; h2 != null ; h2 = h2.next) {
if (h1 == h2) return h1;
}
}
return null;
}
}
- 复杂度分析:
- 时间复杂度O(m*n)
- 空间复杂度O(1):常数的空间。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情”