剑指 Offer 52 两个链表的第一个公共节点
1 题目
2 提示
- 如果两个链表没有交点,返回
null;
- 在返回结果后,两个链表仍须保持原有的结构;
- 可假定整个链表结构中没有循环;
- 程序尽量满足
O(n) 时间复杂度,且仅用 O(1) 内存。
3 示例
输入:A [a1->a2->c1->c2->c3],B [b1->b2->b3->c1->c2->c3]
输出:c1
输入:A [4->1->8->4->5],B [5->0->1->8->4->5]
输出:8
输入:A [2->6->4],B [1->5]
输出:null
4 解题思路
- 双指针法:我们使用两个指针
node1,node2 分别指向两个链表 headA,headB 的头结点,然后同时分别对结点遍历;
- 当
node1 到达链表 headA 的末尾时,重新定位到链表 headB 的头结点;
- 当
node2 到达链表 headB 的末尾时,重新定位到链表 headA 的头结点;
- 这样,当它们相遇时,所指向的结点就是第一个公共结点。
5 复杂度分析
- 时间复杂度:时间复杂度:
O(m+n),其中 m 和 n 是分别是链表 headA 和 headB 的长度。两个指针同时遍历两个链表,每个指针遍历两个链表各一次。
- 空间复杂度:
O(1)。
6 题解
public class JZ52_两链表第一个公共节点 {
public static void main(String[] args) {
ListNode nodeA1 = ListNode.createListNode(new String[]{"a1", "a2"});
ListNode nodeA2 = ListNode.createListNode(new String[]{"b1", "b2", "b3"});
ListNode nodeA3 = ListNode.createListNode(new String[]{"c1", "c2", "c3"});
nodeA1.next = nodeA3;
nodeA2.next = nodeA3;
PrintUtils.getInstance().print(solution(nodeA1, nodeA2).val, "输出");
ListNode nodeB1 = ListNode.createListNode(new int[]{4, 1});
ListNode nodeB2 = ListNode.createListNode(new int[]{5, 0, 1});
ListNode nodeB3 = ListNode.createListNode(new int[]{8, 4, 5});
nodeB1.next = nodeB3;
nodeB2.next = nodeB3;
PrintUtils.getInstance().print(solution(nodeB1, nodeB2).val, "输出");
ListNode nodeC1 = ListNode.createListNode(new int[]{1, 3, 3, 4});
ListNode nodeC2 = ListNode.createListNode(new int[]{5, 6, 7});
PrintUtils.getInstance().print(solution(nodeC1, nodeC2) == null ? "null" : "非null", "输出");
}
private static ListNode solution(ListNode nodeA, ListNode nodeB) {
if (null == nodeA || null == nodeB) return null;
ListNode tempA = nodeA, tempB = nodeB;
while (tempA != tempB) {
tempA = null != tempA ? tempA.next : nodeB;
tempB = null != tempB ? tempB.next : nodeA;
}
return tempA;
}
}