LeetCode_160. 相交链表(哈希表、双指针两种思路 Java)

^ _ ^ 有趣都藏在无聊的日子里,所以保持热爱 @悄悄努力的人er

题目描述:160. 相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

在这里插入图片描述
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。

示例 1:
在这里插入图片描述

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。 在 A 中,相交节点前有 2个节点;在 B 中,相交节点前有 3 个节点。

示例 2:
在这里插入图片描述

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3,skipB = 1
输出:Intersected at ‘2’
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B中,相交节点前有 1 个节点。

示例 3:

在这里插入图片描述

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB= 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。 由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 这两个链表不相交,因此返回 null 。

提示:

  1. listA 中节点数目为 m
  2. listB 中节点数目为 n
  3. 0 <= m, n <= 3 * 10^4
  4. 1 <= Node.val <= 10^5
  5. 0 <= skipA <= m
  6. 0 <= skipB <= n
  7. 如果 listA 和 listB没有交点,intersectVal 为 0
  8. 如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]

思路描述:

思路1:哈希表

若两个链表中有空链表,则这两个链表定不会相交。
在两链表都不为空的情况下,

  1. 创建哈希表,用于存储链表节点
  2. 遍历链表headA,获取每个节点并存入哈希表。(此时,获取的该节点为以当前节点的为头结点的链表。因为当前节点的next方法,可以使一个节点代表一条链表)
    如:listA = [4,1,8,4,5] 。则存入哈希表中的依次为:4、1、8、4、5
    其中8代表 [ 8 , 4 , 5 ]
  3. 遍历链表headB,获取每个节点并在哈希表中查找是否含有该节点,若含有,说明当前节点以及之后节点元素都一样,返回该节点
  4. 遍历结束,返回null,说明未找到相交链表
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //若有链表为空,则不会相交
        if(headA==null || headB==null){
            return null;
        }
        Set<ListNode> set=new HashSet<ListNode>();
        ListNode curr=headA;
        //遍历headA,将每个结点存入集合
        while(curr!=null){
            set.add(curr);
            curr=curr.next;
        }
        curr=headB;
        //遍历headB,在集合中查找是否有当前结点
        while(curr!=null){
            if(set.contains(curr)){
                return curr;
            }
            curr=curr.next;
        }
        return null;
    }
}

在这里插入图片描述

思路2:(双指针)

同样,若两个链表中有空链表,则这两个链表定不会相交。
在两链表都不为空的情况下,
我们发现,若给headA 后面加上headB,headB后面加上headA,此时两链表长度相同,并且在有相交节点情况下,后面几个元素一定相同;
则很容易可以找到相交节点;
例如示例1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
如按上述描述:
listA = 4 --> 1 --> 8 --> 4 --> 5 --> 5 --> 0 --> 1 --> 8 --> 4 --> 5
listB = 5 --> 0 --> 1 --> 8 --> 4 --> 5 --> 4 --> 1 --> 8 --> 4 --> 5

明白了这个原理,我们可以这样实现:定义两个指针 i , j ;

  • 开始时,指针 i 指向headA ,指针 j 指向headB,开始遍历两个链表
  • 当 i 不为null时,更新 i 为 i.next ;当 j 不为null时,更新 j 为 j.next ;
  • 当 i 为null时,更新 i 为 headB ;当 j 为null时,更新 j 为 headA ;
  • 当 i=j 时,分两种情况,1》同时为null,2》找到相交节点,不管那种情况我们只需要返回当前节点即可;
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //若有链表为空,则不会相交
        if(headA==null || headB==null){
            return null;
        }
        ListNode i=headA,j=headB;
        while(i!=j){
            if(i!=null&&j!=null){
                i=i.next;
                j=j.next;
            }
            if(i==null&&j!=null){
                i=headB;
                j=j.next;
            }
            if(i!=null&&j==null){
                i=i.next;
                j=headA;
            }
        }
        return i;

    }
}

在这里插入图片描述

思路2优化代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //若有链表为空,则不会相交
        if(headA==null || headB==null){
            return null;
        }
        ListNode i=headA,j=headB;
        while(i!=j){
            i=i==null?headB:i.next;
            j=j==null?headA:j.next;
        }
        return i;

    }
}

在这里插入图片描述
最后,附上题目链接:
https://leetcode-cn.com/problems/intersection-of-two-linked-lists/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值