JZ52 两个链表的第一个公共结点


输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

数据范围: n≤1000
要求:空间复杂度 O(1),时间复杂度 O(n)

例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:

输入描述:
输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。
返回值描述:
返回传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表。

示例1
输入:{1,2,3},{4,5},{6,7}
返回值:{6,7}
说明:
第一个参数{1,2,3}代表是第一个链表非公共部分,第二个参数{4,5}代表是第二个链表非公共部分,最后的{6,7}表示的是2个链表的公共部分
这3个参数最后在后台会组装成为2个两个无环的单链表,且是有公共节点的
示例2
输入:{1},{2,3},{}
返回值:{}
说明:2个链表没有公共节点 ,返回null,后台打印{}

思路一 Set或List第一个链表,遍历第二个链表找相同节点

把第一个链表放入Set或者List,然后遍历第二个链表,返回第二个链表中第一个包含在Set或者List中的节点,没有返回null
代码:

import java.util.*;
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
        Set<ListNode> listNode1 = new HashSet<>(); //这里执行没有问题,但是在牛客会有红色波浪下划线,不太清除是什么原因,但是提交成功了
        while (pHead1 != null) {
            listNode1.add(pHead1);
            pHead1 = pHead1.next;
        }
        if (!listNode1.isEmpty()) {
            while(pHead2!=null){
                if(listNode1.contains(pHead2)){
                    return pHead2;
                }else{
                    pHead2 = pHead2.next;
                }
            }
        } 
        return null;
    }
}

思路二 双指针

两个指针,一个指针从第一个链表开始,走完之后走第二个链表;一个指针从第二个链表开始,走完之后走第一个链表,这两个指针走过的长度是相同的。如果有公共链表,两个链表长度相同的话,两个指针在遍历自己的链表时就会在第一个公共节点相遇;在两个链表长度不同的情况下,那两个指针在走另一个链表的时候,最后的公共部分必然是同步去走的,会在第一个公共节点相遇。

我描述的黏黏糊糊的,看看别人的描述吧:
使用两个指针 a,b 分别指向两个链表 pHead1,pHead2的头结点,然后同时分别逐结点遍历,当 a 到达链表 pHead1的末尾时,重新定位到链表 pHead2的头结点;当 b 到达链表 pHead2 的末尾时,重新定位到链表 pHead1的头结点。当双指针相遇时,所指向的结点就是第一个公共结点

1.指针a、b分别在pHead1、pHead2上同时行走
2.当指针a走到pHead1最后一个节点5时,指针b指向pHead2节点4
3.指针a指向pHead2头节点,此时指针b指向pHead2最后一个节点5
4.指针b指向pHead1头节点,双指针继续走
5.当双指针在pHead1、pHead2的节点3处相遇,节点3即为双链表第一个公共节点

上代码:

import java.util.*;
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
        ListNode head1 = pHead1;
        ListNode head2 = pHead2;

        int num1 = 0;
        int num2 = 0;

        while(num1<=1 && num2<=1){
            if(head1!=head2){
                head1 = head1.next;
                head2 = head2.next;
                if(head1==null){
                    head1 = pHead2;
                    num1+=1;
                }
                if(head2==null){
                    head2 = pHead1;
                    num2+=1;
                }
            }else{
                return head1;
            }
        }
        return null;
    }
}

思路三 统计链表长度,长的先走,同样长度再一起走

这是看到其他人的思路,感觉思路跟上面双指针很类似,只是表现方式不同
先统计两个链表的长度,如果两个链表的长度不一样,就让链表长的先走,直到两个链表长度一样,这个时候两个链表再同时每次往后移一步,看节点是否一样,如果有相等的,说明这个相等的节点就是两链表的交点,否则如果走完了还没有找到相等的节点,说明他们没有交点,直接返回null即可

代码:

import java.util.*;
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
        ListNode head1 = pHead1;
        ListNode head2 = pHead2;

        int num1 = getLength(pHead1);
        int num2 = getLength(pHead2);
        int num = num1 - num2;
        if (num > 0) {
            head1 = getListNode(head1, num);
        } else if (num < 0) {
            head2 = getListNode(head2, num * (-1));
        }

        while (head1 != head2) {
            head1 = head1.next;
            head2 = head2.next;
        }
        return head1;
    }

    private int getLength(ListNode head) {
        int num = 0;
        while (head != null) {
            num += 1;
            head = head.next;
        }
        return num;
    }

    private ListNode getListNode(ListNode head, int num) {
        while (num > 0) {
            head = head.next;
            num -= 1;
        }
        return head;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值