输入两个链表,找出它们的第一个公共节点

题目:输入两个链表,找出它们的第一个公共节点

方法一:哈希和集合

先将一个链表元素全部存到Map里,然后一边遍历第二个链表,一边检测Hash中是否存在当前结点,如果有交点,那么一定能检测出来。


/**
 * 使用集合查找两个链表的第一个公共节点。
 * @param headA 第一个链表的头节点。
 * @param headB 第二个链表的头节点
 * @return 第一个公共节点,如果不存在公共节点则返回null。
 */
public ListNode findFirstCommonNodeBySet(ListNode headA, ListNode headB) {
    // 创建一个集合来存储链表A的节点
    Set<ListNode> set = new HashSet<>();
 
    // 遍历链表A,将每个节点添加到集合中
    while (headA != null) {
        set.add(headA);
        headA = headA.next;
    }
 
    // 遍历链表B,检查每个节点是否存在于集合中
    while (headB != null) {
        if (set.contains(headB))
            return headB; // 找到第一个公共节点
        headB = headB.next;
    }
 
    return null; // 未找到公共节点
}

方法二:栈

需要用到两个空间为o(n)的栈,分别将两个链表的节点入两个栈,然后出栈,如果两个节点相等就继续出栈,直到找到最晚出栈的那组。

stack.push(a):将a元素入栈

stack.peek() :获取到栈顶部的元素

stack.pop() :从栈中移除并返回栈顶的元素

import java.util.Stack;
 
/**
 * 使用栈查找两个链表的第一个公共节点。
 * @param headA 第一个链表的头节点。
 * @param headB 第二个链表的头节点
 * @return 第一个公共节点,如果不存在公共节点则返回null。
 */
public ListNode findFirstCommonNodeByStack(ListNode headA, ListNode headB) {
    // 创建两个栈,分别用于存储链表A和链表B的节点
    Stack<ListNode> stackA = new Stack<>();
    Stack<ListNode> stackB = new Stack<>();
    
    // 遍历链表A,将每个节点压入栈中
    while (headA != null) {
        stackA.push(headA);
        headA = headA.next;
    }
    
    // 遍历链表B,将每个节点压入栈中
    while (headB != null) {
        stackB.push(headB);
        headB = headB.next;
    }
    
    // 从栈顶开始比较两个栈的节点,找到第一个不相等的节点即为分叉点,其前一个节点即为第一个公共节点
    ListNode preNode = null;
    while (!stackA.isEmpty() && !stackB.isEmpty()) {
        if (stackA.peek() == stackB.peek()) {
            preNode = stackA.pop();
            stackB.pop();
        } else {
            break;
        }
    }
    
    return preNode;
}

方法三:差和双指针

公共节点一定存在第一轮遍历,那么La的长度为L1,Lb的长度为L2,长度差的绝对值为|L1-L2|;第二轮遍历让长的先走|L1-L2|步,然后再同时向前走,直到找到相同节点即为公共节点。

public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
     if(pHead1==null || pHead2==null){
             return null;
         }
        ListNode current1=pHead1;
        ListNode current2=pHead2;
        int l1=0,l2=0;
        //分别统计两个链表的长度
        while(current1!=null){
            current1=current1.next;
            l1++;
        }
        
         while(current2!=null){
            current2=current2.next;
            l2++;
        }
//将current的值变回头节点
        current1=pHead1;
        current2=pHead2;
        int sub=l1>l2?l1-l2:l2-l1;
        //长的先走sub步
       if(l1>l2){
           int a=0;
           while(a<sub){
            current1=current1.next;
            a++;
        }   
       }
      
       if(l1<l2){
           int a=0;
           while(a<sub){
            current2=current2.next;
            a++;
        }   
       }
        //同时遍历两个链表,当值相当的时候就可以返回节点了
       while(current2!=current1){
          current2=current2.next;
          current1=current1.next;
       } 
        
        return current1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值