Java 判断两个链表是否相交

本文介绍了两种方法判断两个链表是否相交。方法一是双重循环遍历,时间复杂度为O(m×n);方法二是利用长度差,先移动长链表指针,再同时遍历,时间复杂度为O(n)。优化后的算法提高了效率。

问题描述

判断两个链表是否相交,如果两个链表相交,两个链表有相同的结点,如图所示:
在这里插入图片描述

方法一

方法描述

最简单粗暴地方法可以设置两个变量分别遍历两个链表,双重for循环,在循环遍历过程中,如果两个变量相等,那么两个链表相交。

动画演示

1367f142d.gif)

代码如下

/**
 * Definition for singly-linked list.
 * public class Node {
 *     int val;
 *     Node next;
 *     Node() {}
 *     Node(int val) { this.val = val; }
 *     Node(int val, Node next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public boolean isIntersect(SingleLink link) {
         //判断链表是否为null
    	if(link == null) {
    		return false;
    	}
    	
    	for(Node p = head; p != null; p = p.next){
			for(Node q = link.head; q != null; q = q.next) {
					if( p == q) {
						return true;
					}
   			}
        }
        return false;
    }
}

时间复杂度

假设链表1的长度为m,链表2的长度为n,该方法在双重for循环下的时间复杂度为:O(m × n)

方法二

方法描述

判断两个链表是否相交,该两个链表中长度必定有长有短,或者相等,想到这两个的链表长度问题,我们可以得到两个链表的长度的差值diff。同样也是设置两个变量p,q,分别遍历长链表和短链表,与方法一不同的是,p遍历长链表的时候不是从第一个结点开始遍历,而是先让p往后移动diff个结点,然后p和q同时循环往后一个结点,如果p == q,那么两个链表就相交。

动画演示

在这里插入图片描述

代码如下

/**
 * Definition for singly-linked list.
 * public class Node {
 *     int val;
 *     Node next;
 *     Node() {}
 *     Node(int val) { this.val = val; }
 *     Node(int val, Node next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
	 //求链表长度
   	 private int size() {
        int count = 0;
        for (Node p = head; p != null; p = p.next) {
            count++;
        }
        return count;
    }
    //判断两个链表是否相交
    public boolean isIntersect(SingleLink link) {
        //安全检测
        if (link == null) {
            return false;
        }
     	int size_cur = size();//当前链表长度
        int size_link = link.size();//传进来的链表长度

		//p指向长链表的第一个结点  q指向短链表的第一个结点
        Node p = size_cur > size_link ? this.head : link.head;
        Node q = size_cur > size_link ? link.head : this.head;
        //求两个链表长度差
        int diff = Math.abs(size_cur - size_link);
        //p先往后移动diff个结点
        while (diff-- > 0) {
            p = p.next;
        }
		
		//p 和 q同时往后移动
        while (p != q) {
            p = p.next;
            q = q.next;
        }
        
        //如果p(q)不为null,则两个链表相交,否则不相交
        if(p != null) {
        	return true;
        }else {
        	return false;
        }
}

时间复杂度

因为p和q是同时往后移动的,所以时间复杂度为O(n),小于方法一的时间复杂度O(m × n)。

<think>好的,我现在需要帮助用户了解如何用Java判断两个链表是否相交。首先,我得回想一下链表相交的定义。链表相交指的是两个链表在某个节点之后合并,形成共同的部分。也就是说,从相交节点开始,后续的所有节点都是相同的,直到链表结束。 接下来,我得确定用户的需求。用户可能正在学习数据结构,或者在面试准备中遇到了这个问题。他们需要具体的实现方法,而不仅仅是理论上的解释。因此,我应该提供清晰的思路和代码示例,同时考虑时间和空间复杂度。 首先,我得回顾常见的解决方法。常见的方法有两种:哈希表法和双指针法。哈希表法的思路是遍历第一个链表,将每个节点的引用存入哈希表,然后遍历第二个链表,检查是否有节点存在于哈希表中。这种方法的时间复杂度是O(m+n),空间复杂度也是O(m+n),其中m和n分别是两个链表的长度。 另一种方法是双指针法,也称为“走尾指针法”。这种方法不需要额外空间,时间复杂度同样是O(m+n)。具体步骤是:首先遍历两个链表,找到各自的尾节点,并记录长度。如果尾节点不同,说明不相交;如果相同,则计算两个链表的长度差,让较长的链表的指针先移动差值步,然后两个指针同时移动,直到相遇,相遇点即为相交节点。 用户可能更倾向于高效的方法,尤其是空间复杂度低的解决方案。因此,我应该重点解释双指针法,因为它更优。同时,我需要考虑链表可能存在的环的情况,但通常在这种情况下,题目假设链表无环,所以可能不需要处理环的问题,但最好在注意事项中提及。 然后,我需要考虑如何用Java实现双指针法。首先,定义链表节点的结构,通常是一个包含数据和next指针的类。然后,编写函数来检查相交。具体步骤包括遍历链表获取长度和尾节点,比较尾节点是否相同,调整指针起点,同步遍历直到找到相同节点。 在代码实现中,需要注意边界情况,例如其中一个链表为空,或者两个链表长度相差较大。此外,测试用例的构造也很重要,例如创建相交链表和不相交链表来验证代码的正确性。 可能用户还会有疑问,比如如何处理有环的情况,或者是否有其他方法。虽然问题通常假设链表无环,但可以简要说明如果有环的话需要先检测环,然后再处理相交的问题,但这会增加复杂度。 最后,总结思路和步骤,确保用户能够理解并实现该算法。同时,强调时间和空间复杂度,帮助用户评估不同方法的优劣。</think>--- 要判断两个链表是否相交,关键在于找到**相交节点**(两个链表的公共节点)。Java中可通过以下两种方法实现: --- ### 方法一:哈希表法 **核心思路**:遍历链表A,将所有节点存入哈希表,再遍历链表B,检查节点是否存在于哈希表中。 **时间复杂度**:$O(m + n)$,空间复杂度:$O(m)$(m、n为链表长度) ```java import java.util.HashSet; public class LinkedListIntersection { static class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } public ListNode getIntersectionNode(ListNode headA, ListNode headB) { HashSet<ListNode> visited = new HashSet<>(); // 遍历链表A,存储所有节点 while (headA != null) { visited.add(headA); headA = headA.next; } // 遍历链表B,检查哈希表 while (headB != null) { if (visited.contains(headB)) { return headB; } headB = headB.next; } return null; } } ``` --- ### 方法二:双指针法(推荐) **核心思路**: 1. 若两链表相交,则**尾节点必相同** 2. 计算两链表长度差,对齐起点后同步遍历 **时间复杂度**:$O(m + n)$,空间复杂度:$O(1)$ ```java public class LinkedListIntersection { static class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null) return null; // 计算链表A和B的长度 int lenA = getLength(headA), lenB = getLength(headB); // 对齐起点:长链表先走差值步 ListNode pA = headA, pB = headB; if (lenA > lenB) { for (int i = 0; i < lenA - lenB; i++) pA = pA.next; } else { for (int i = 0; i < lenB - lenA; i++) pB = pB.next; } // 同步遍历找交点 while (pA != null && pB != null) { if (pA == pB) return pA; pA = pA.next; pB = pB.next; } return null; } private int getLength(ListNode node) { int len = 0; while (node != null) { len++; node = node.next; } return len; } } ``` --- ### 方法三:巧妙双指针遍历(无长度计算) **核心思想**:两指针分别遍历A+B和B+A路径,最终会在交点相遇(若存在)。 ```java public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null) return null; ListNode pA = headA, pB = headB; // 当pA和pB走过相同路径长度时: // - 若相交,会在交点相遇 // - 若不相交,最终同时为null退出循环 while (pA != pB) { pA = (pA == null) ? headB : pA.next; pB = (pB == null) ? headA : pB.next; } return pA; } ``` --- ### 验证相交的关键条件 1. **尾节点相同**:若两链表尾节点不同,则一定不相交 2. **节点引用相同**:判断相交的依据是节点对象地址相同,而非值相等 --- ### 测试用例示例 ```java public static void main(String[] args) { // 构造相交链表 ListNode common = new ListNode(8); common.next = new ListNode(4); common.next.next = new ListNode(5); ListNode headA = new ListNode(4); headA.next = new ListNode(1); headA.next.next = common; ListNode headB = new ListNode(5); headB.next = new ListNode(6); headB.next.next = new ListNode(1); headB.next.next.next = common; // 调用方法判断 ListNode result = getIntersectionNode(headA, headB); System.out.println(result != null ? "相交节点值:" + result.val : "不相交"); } ``` --- ### 复杂度对比 | 方法 | 时间复杂度 | 空间复杂度 | 适用场景 | |------------|------------|------------|--------------------| | 哈希表法 | $O(m+n)$ | $O(m)$ | 需要快速实现 | | 双指针法 | $O(m+n)$ | $O(1)$ | 内存敏感场景 | | 路径对齐法 | $O(m+n)$ | $O(1)$ | 代码简洁,无需长度 | --- ### 注意事项 1. 若链表可能有环,需先检测环再判断相交(经典相交问题通常假设无环) 2. 节点值可以重复,判断依据是节点引用地址相同而非值相等 3. 空链表直接返回`null`
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WYSCODER

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值