判断两个链表是否相交

题目描述:

判断两个链表(可能有环可能无环)之间是否有相交(此处相交指链表经过了同一个地址的节点(与节点的值无关)) 。如果相交,则返回相交的第一个节点。否则,返回null

前置知识点:判断链表是否有环,并找出第一个成环节点:

法1:使用HashSet的方法来判断是否经过了重复节点

代码及解析:

复制代码
 1 public static Node getLoopList1(MyLink list) {
 2         Node p = list.head;
 3         HashSet<Node> set = new HashSet<>();//利用HashSet中元素不可重复的特性
 4         while (p != null) {
 5             if (set.contains(p) == false) {
 6                 set.add(p);
 7             }
 8             else {//出现重复节点,说明有环结构
 9                 return p;
10             }
11             p = p.next;
12         }
13         return null;
14     }
复制代码

 

法2:使用快慢指针的方法来判断

代码及解析:

复制代码
 1 public static Node getLoopList2(MyLink list) {
 2         //因为快指针第一次要走两步,为了避免越界,先讨论掉这些情况
 3         if (list.head == null || list.head.next == null || list.head.next.next == null) {
 4             return null;
 5         }
 6         //建立一个快慢指针
 7         Node fast = list.head, slow = list.head;
 8         boolean isChainList = false;
 9         while (fast.next != null && fast != null) {//如果有环,快慢指针一定会相遇
10             fast = fast.next.next;
11             slow = slow.next;
12             if (slow == fast) {
13                 isChainList = true;
14                 break;
15             }
16         }
17         if (isChainList == false) {
18             return null;
19         }
20         //将快指针移回起点,慢指针原地不动,两者一次移动一格,则相遇的点为环的起点(证明过程复杂)
21         fast = list.head;
22         while (fast != slow) {
23             fast = fast.next;
24             slow = slow.next;
25         }
26         return fast;
27     }
复制代码

 

在前置知识点的基础上,接下来来解决这个问题

分三类情况讨论:

1.两个链表都是无环的:

思路:分别得到两个链表的长度差值,然后让长的那条链表指针走差值步后,让两个链表的指针同时向右走,先判断尾节点是否相同,如果相同则有相交节点,防止则无相交节点
      当两个节点指向同一个节点时,则返回这个所要的节点

代码及解析:

复制代码
 1 public static Node noLoop(MyLink list1,MyLink list2) {
 2         int n = 0;//获得两链表长度的差值 
 3         Node cur1 = list1.head, cur2 = list2.head;
 4         while (cur1.next != null) {
 5             n++;
 6             cur1 = cur1.next;
 7         }
 8         while (cur2.next != null) {
 9             n--;
10             cur2 = cur2.next;
11         }
12         if (cur1 != cur2) {//两链表尾节点不同,两者一定没有相交节点
13             return null;
14         }
15         //已经确定一定有相交节点,现在找出第一个相交节点
16         cur1 = n > 0 ? list1.head : list2.head;//cur1为长链表的指针
17         cur2 = n > 0 ? list2.head : list1.head;//cur2为短链表的指针
18         //让长链表先走n步
19         n = Math.abs(n);
20         for (int i = 0; i < n; i++) {
21             cur1 = cur1.next;
22         }
23         //之后让两链表指针同时右走,直到指向相同节点为止
24         while (cur1 != cur2) {//
25             cur1 = cur1.next;
26             cur2 = cur2.next;
27         }
28         return cur1;
29     }
复制代码

 

2.一个链表有环一个链表无环:一定没有相交的节点(可通过画图分析证明)

 

3.两个链表都有环:

思路:在有相交情况下,要分两种情况考虑:
(1).在成环之前就已经相交:则将其转为无环的情况,把第一个成环节点作为尾节点即可
(2).在环中有相交:则遍历其中一个链表(直到转了一圈为止),如果经过了另一个链表的环起始点则有相交

代码及解析:

复制代码
 1 public static Node bothLoop(MyLink list1,Node loop1,MyLink list2,Node loop2) {
 2         Node cur1 = list1.head;
 3         Node cur2 = list2.head;
 4         if (loop1 == loop2) {//在成环前就相交的情况下,寻找相交的第一个节点(转成无环模型)
 5             int n = 0;
 6             while (cur1.next != loop1) {
 7                 n++;
 8                 cur1 = cur1.next;
 9             }
10             while (cur2.next != loop1) {
11                 n--;
12                 cur2 = cur2.next;
13             }
14             cur1 = n > 0 ? list1.head : list2.head;
15             cur2 = n > 0 ? list2.head : list1.head;
16             n = Math.abs(n);
17             for (int i = 0; i < n; i++) {
18                 cur1 = cur1.next;
19             }
20             while (cur1 != cur2) {
21                 cur1 = cur1.next;
22                 cur2 = cur2.next;
23             }
24             return cur1;
25         }
26         else {//说明就算有相交节点也在环后  或  根本没有相交节点
27             cur1 = loop1.next;//直接从环中去寻找有没有相交节点
28             while (cur1 != loop1) {
29                 if (cur1 == loop2) {
30                     return loop2;//也可以return loop1,两者都可认为是相交的第一个节点
31                 }
32                 cur1 = cur1.next;
33             }
34             return null;//否则就没有公共节点
35         }
36     }
复制代码

 

最后对这三种情况进行总结,得到一个总结性函数:

复制代码
 1 //最后对三种情况进行总结得到一个函数:
 2     public static Node getIntersectNode(MyLink list1,MyLink list2) {
 3         Node head1 = list1.head;
 4         Node head2 = list2.head;
 5         if (head1 == null || head2 == null) {
 6             return null;
 7         }
 8         Node loop1 = ChainList.getLoopList2(list1);
 9         Node loop2 = ChainList.getLoopList2(list2);
10         if (loop1 == null && loop2 == null) {
11             return noLoop(list1,list2);
12         }
13         else if (loop1 != null && loop2 != null) {
14             return bothLoop(list1,loop1,list2,loop2);
15         }
16         else {
17             return null;
18         }
19     }
复制代码

 

posted @   jue1e0  阅读(379)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示