LeetCode160. 相交链表问题的三种解法

  • 注: 这也是程序员面试金典中的02.07题、剑指offer中的第52题

1. 问题描述及分析

在这里插入图片描述
如果只学过java,而不了解指针的话其实难以理解题目,为什么示例1中的值为1的节点不是相交的节点呢?

其实可以这样理解,链表A和B中虽然都有值为1的节点,但这两个节点存储的位置不同,比如A中值为1的节点存储的位置为0x33ff,B中值为1的节点存储的位置为0x0011,但是从8开始,所有的节点存储的值和位置都相同,所以值为8的节点是相交的起始节点。

Java中判断两个节点是否相同可以直接用==判断

2. 解题思路及代码

思路参考:
作者:sdwwld
链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/solution/ji-he-shuang-zhi-zhen-deng-3chong-jie-jue-fang-s-3/
来源:力扣(LeetCode)

主要有3种解题思路:

2.1 方法一:用Set集合来判断

  • 做这题最容易想到的解决方式是,先把第一个链表的节点全部存放到集合set中,然后遍历第二个链表的每一个节点,判断在集合set中是否存在,如果存在就直接返回这个存在的结点。如果遍历完了,在集合set中还没找到,说明他们没有相交,直接返回null即可。
  • 代码如下:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;
        Set<ListNode> set = new HashSet<>();
        // 将A链表遍历,并将所有节点存放Set集合种
        while (curA != null){
            set.add(curA);
            curA = curA.next;
        }
        while (curB != null){
            if (set.add(curB)){
                curB = curB.next;
            }else {
            	// 如果向set中添加节点失败,证明当前节点就是相同的节点
                return curB;
            }
        }
        // 如果至少有一个链表为空,或者两个链表都添加成功,证明没有相同节点,返回null
        return null;
    }
  • 提交结果:
    在这里插入图片描述

2.2 方法二: 先将两个链表对齐

如果两个链表长度相同,那就可以同时遍历两个链表,然后逐个判断,难点在于两个链表长度不同的情况。
其实也很简单,如果两个链表的长度不一样,就让链表长的先走,直到两个链表长度一样,这个时候两个链表再同时每次往后移一步,看节点是否一样,如果有相等的,说明这个相等的节点就是两链表的交点,否则如果走完了还没有找到相等的节点,说明他们没有交点,直接返回null即可。如下图所示:
在这里插入图片描述

  • 代码如下:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;

        int lenA = len(headA);
        int lenB = len(headB);
        while (lenA != lenB){
            if (lenA > lenB){
                // A链表比较长
                curA = curA.next;
                lenA --;
            }else {
                // B链表比较长
                curB = curB.next;
                lenB--;
            }
        }
        // 同时遍历
        while (curA != curB){
            curA = curA.next;
            curB =curB.next;
        }
        return curA;
    }
    // 求链表长度
    private int len(ListNode head){
        int res = 0;
        while (head != null){
            res++;
            head = head.next;
        }
        return res;
    }
  • 执行结果:
    在这里插入图片描述

2.2 方法三:双指针解决

思路是,假设链表A和B的长度不同,但是A+B和B+A的长度是相等的,或者说,先遍历A然后再遍历B,与先遍历B再遍历A走的长度是相等的,并且如果有相同点,两种遍历方法会在相同点处相遇。

下面,具体展开讲一讲。

两个指针,最开始的时候一个指向链表A,一个指向链表B,然后他们每次都要往后移动一位,顺便查看节点是否相等。如果链表A和链表B不相交,基本上没啥可说的,我们这里假设链表A和链表B相交。那么就会有两种情况:

  • 一种是链表A的长度和链表B的长度相等,他们每次都走一步,最终在相交点肯定会相遇。
  • 一种是链表A的长度和链表B的长度不相等,如下图所示

在这里插入图片描述
在这里插入图片描述
虽然A和B有交点,但因长度不同,所以他们完美的错开了,即使把链表都走完了也找不到相交点。

我们仔细看上面的图,如果A指针把链表A走完了,然后再从链表B开始走到相遇点就相当于把这两个链表的所有节点都走了一遍,同理如果B指针把链表B走完了,然后再从链表A开始一直走到相遇点也相当于把这两个链表的所有节点都走完了。

所以如果A指针走到链表末尾,下一步就让他从链表B开始。同理如果B指针走到链表末尾,下一步就让他从*链表A开始。只要这两个链表相交最终肯定会在相交点相遇,如果不相交,最终他们都会同时走到两个链表的末尾,不妨画个图看一下:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
如上图所示,A指针和B指针如果一直走下去,那么他们最终会在相交点相遇。下面简单证明一下,参考

  1. 设长链表A长度为LA,短链表长度LB;
  2. 由于遍历速度相同,则在长链表A走完LA长度时,短链表B已经反过头在A上走了LA-LB的长度,剩余要走的长度为LA-(LA-LB) = LB;
  3. 之后长链表A要反过头在B上走,剩余要走的长度也是LB;
  4. 也就是说目前两个链表“对齐”了。因此,接下来遇到的第一个相同节点便是两个链表的交点。
  • 代码如下:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode nodeA = headA;
        ListNode nodeB = headB;

        while (nodeA != nodeB){
            nodeA = nodeA == null ? headB : nodeA.next;
            nodeB = nodeB == null ? headA : nodeB.next;
        }
        return nodeA;
    }
  • 提交结果:
    在这里插入图片描述
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值