剑指offer 36. 两个链表的第一个公共结点

36. 两个链表的第一个公共结点

题目描述

输入两个链表,找出它们的第一个公共结点。

法一:双指针法 ,复杂度O(2n)

两个指针同时遍历两个链表,每个指针遍历完当前链表继续遍历另一链表,当两个指针相等或者某个指针为空时退出循环

定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点

假定 p1 指向表 a , p2 指向表 b, 两个链表公共结点之后的长度肯定相等,因为是同一段链表。所以长度不等只能来自公共结点之前的部分。

两个链表的第一个公共结点之前的长度要么相等,要么不相等,如果相等,那么两个指针 p1 , p2 同时后移,肯定能同时找到公共结点;如果两个链表的长度不一样,那么比如 a 链表比 b 链表长 k 个结点,那么当 p2 到达 b 链表的表尾的时候,p1 肯定距离到达 a 链表表尾还差 k 个结点,随后 p2 开始从 a 链表的表头开始遍历。当 p1 链表到达表尾时后,p1 从 b 链表的表头开始遍历, 此时 p2 已经在 a 链表上走了 k 个结点,而 p1 在 b 链表上 才刚起步,走了 0 个结点,而恰好 a 就比 b 长 k 个结点,所以 p1 和 p2 会同时到达 公共结点。

链表1 在公共结点之前的结点个数 为 a1, 公共结点之后的结点个数为 a2, 同理,链表2 在公共结点之前的结点个数为 b1, 公共结点之后的结点个数为 b2, 因为公共结点的之后的部分是同一条链表,所以a2 == b2, 所以上面的思路就是 a1 + b1 == b1 + a1

 1 public class Solution {
 2     public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
 3         if(pHead1 == null || pHead2 == null){
 4             return null;
 5         }
 6         ListNode p1 = pHead1;
 7         ListNode p2 = pHead2;
 8         while(p1 != p2 && (p1 != null && p2 != null)){
 9             p1 = p1.next;
10             p2 = p2.next;
11             if(p1 != p2){
12                 if(p1 == null) 
13                     p1 = pHead2;
14                 if(p2 == null)
15                     p2 = pHead1;
16             }
17         }
18        return p1;
19     }
20 }

你变成我,走过我走过的路。

我变成你,走过你走过的路。

然后我们便相遇了..

复杂度分析:

 1 public class Solution {
 2     public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
 3         
 4         // 两个指针同时遍历两个链表,每个指针遍历完当前链表继续遍历另一链表,当两个指针相等或者某个指针为空时退出循环
 5         ListNode p1 = headA, p2 = headB;
 6         while(p1 != p2){
 7             p1 = (p1 != null) ? p1.next : headB;
 8             p2 = (p2 != null) ? p2.next : headA;
 9         }
10         return p1;
11     }
12 }

leetcode运行时间为1ms, 空间为41.4MB

复杂度分析:

时间复杂度:最多把两个链表合起来遍历一遍,所以时间复杂度为O(M+N)

空间复杂度:O(1)

法二:双重循环法, 算法复杂度 O(n^2)

 1 public class Solution {
 2     public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
 3          // 双重循环遍历两个链表
 4         ListNode cur1 = pHead1;
 5         while(cur1 != null){
 6             ListNode cur2 = pHead2;
 7             while(cur2 != null){
 8                 if(cur2 == cur1)
 9                     return cur1;
10                 cur2 = cur2.next;
11             }
12             cur1 = cur1.next;
13         }
14         return cur1;
15     }
16 }

法三:

把 其中一个链表存入HashSet中,遍历第二个链表,判断该结点是否存在于HashSet中,如果存在的话直接返回该结点

原文地址:https://www.cnblogs.com/hi3254014978/p/12347735.html