52_剑指offer_java_两个链表的第一个公共节点

本文介绍了一种寻找两个链表首个公共节点的算法,通过分析时间与空间复杂度,提供了两种解决方案:使用栈和利用链表长度差遍历。文章详细讲解了每种方法的实现过程,帮助读者深入理解链表操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

题目描述

测试用例

题目考点

解题思路

用栈解题

规律解题

参考解题

用栈解题

规律解题


题目描述

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

链表节点定义如下:

/**
 * 链表节点
 * @Author rex
 * 2018/9/4
 */
public class ListNode {
    int value;
    ListNode next;
}

 

测试用例

  • 功能测试(输入的两个链表有公共节点:第一个公共节点在链表的中间,第一个公共节点在链表的尾部,第一个公共节点是链表的头节点;输入的两个链表没有公共节点)
  • 特殊输入测试(输入的链表头节点是空指针)

 

题目考点

  • 考察应聘者对时间复杂度和空间复杂度的理解及分析能力。解决这道题有多种不同的思路。每当应聘者想到一种思路的时候,都要很快分析出这种思路的时间复杂度和空间复杂度各是多少,并找到可以优化的地方。
  • 考察应聘者对链表的编程能力。

 

解题思路

首先我们要联想到这样一张图:

offer52

 

然后我们就会有下面的解法:

 

用栈解题

对于上面那张图,我们会想到我们只要从链表的尾部开始遍历。那么最后一个相同的节点就是我们要找的节点。但是单向链表不能从尾开始遍历,所以我们要借助栈的后进先出特点实现从尾部遍历,。

这种算法:时间复杂度为O(m+n),空间复杂度也是O(m+n)

 

规律解题

我们可以先遍历出他们的长度,他们的长度之差就是长的链表需要先走的步数。长链表先走完长度之差,他们就可以同时开始遍历了,直到他们遇到第一个相同的节点

这种算法:时间复杂度是O(m+n),空间复杂度为O(1)

 

参考解题

 

用栈解题

import java.util.Deque;
import java.util.ArrayDeque;

/*
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;
        }
        
       // JDK建议双向队列Deque优先于Stack
        Deque<ListNode> s1= new ArrayDeque<>();
        Deque<ListNode> s2= new ArrayDeque<>();
        ListNode commonNode = null;
        // 链表入栈
        while (pHead1 != null) {
            s1.push(pHead1);
            pHead1 = pHead1.next;
        }
        while (pHead2 != null) {
            s2.push(pHead2);
            pHead2 = pHead2.next;
        }
        // 逐个弹出栈顶元素比较,commonNode储存同节点
        while(!s1.isEmpty() && !s2.isEmpty()){
            if(s1.peek() == s2.peek()){
                commonNode = s1.peek(); 
            }
            s1.pop();
            s2.pop();
        }
        // 
        return commonNode;
    }
}

规律解题

/*
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;
        }
        
        // --------获取长度、长度差-------------- 
        int lengthL1 = getLength(pHead1);
        int lengthL2 = getLength(pHead2);
        int lengthDf = Math.abs(lengthL1 - lengthL2);
        
        // --------按照规律遍历------------------
        ListNode longListHead = pHead1;
        ListNode shortListHead = pHead2;
        if(lengthL2 > lengthL1){ 
             longListHead = pHead2;
             shortListHead = pHead1;
        }
        
        // 长链表先走长度之差步
        for(int i = 0; i < lengthDf; ++i){
            longListHead = longListHead.next;
        }
        // 然后两条链表同时走
        while((longListHead != null) && (shortListHead != null) && (longListHead != shortListHead)){
            // 当前节点不为空,当前节点不相同,则遍历
            longListHead = longListHead.next;
            shortListHead = shortListHead.next;
        }
        // 第一个公共节点
        ListNode firstCommonNode = longListHead;
        return firstCommonNode;
    }
    
    // 功能函数,获取链表长度
    public int getLength(ListNode pHead){
        // 异常
        if(pHead == null){
            return 0;
        }
        ListNode pNode = pHead;
        int length = 0;
        while(pNode != null ){
            // 当前节点不为空,则遍历
            ++length;
            pNode = pNode.next;
        }
        return length;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值