LeetCode 热题 HOT 100 (160. 相交链表)

1. 链表的基本概念(面向初学者)

什么是链表?

链表是一种数据结构,由多个节点(Node)组成。
每个节点包含 两个部分

  1. 数据部分:存储实际的数据,比如 整数字符串 等。
  2. 指针部分:存储指向下一个节点的地址,告诉我们下一个节点在哪里。

在 Java 中,我们可以用一个 类(Class) 来定义链表的 节点(Node)

class ListNode {
    int val; // 存储数据
    ListNode next; // 指向下一个节点
    ListNode(int val) { 
        this.val = val;
        this.next = null; // 初始时,没有下一个节点
    }
}

这样,每个 ListNode 对象代表链表中的一个 节点


2. 题目分析:寻找两个链表的交点

题目描述

  • 输入:给定两个链表 headAheadB
  • 输出:找到 第一个 相交的节点,如果没有交点,返回 null

示例链表结构

链表A:a1 -> a2 -> c1 -> c2 -> c3
链表B:b1 -> b2 -> b3 -> c1 -> c2 -> c3

c1 开始,两个链表合并,形成交点


3. 解题思路

核心思路

  1. 计算两个链表的长度(找到哪个链表更长)。
  2. 调整起点:让较长的链表先走几步,使得两个链表的起点对齐。
  3. 同步遍历:从相同的位置同时遍历,找到第一个相交的节点。

4. Java 代码实现

// 定义链表的节点结构
class ListNode {
    int val;       // 节点存储的数据
    ListNode next; // 指向下一个节点的指针

    ListNode(int val) {
        this.val = val;
        this.next = null; // 初始时,没有指向下一个节点
    }
}

public class Solution {
    
    // 计算链表长度的辅助方法
    public int getLength(ListNode head) {
        int length = 0;
        while (head != null) {
            length++;      // 每遍历一个节点,长度加1
            head = head.next; // 移动到下一个节点
        }
        return length;
    }

    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // 计算两个链表的长度
        int lenA = getLength(headA);
        int lenB = getLength(headB);
        
        // **让较长的链表先走几步**
        while (lenA > lenB) {
            headA = headA.next; // A比B长,就让A先走
            lenA--;             // A向前走一步,长度减1
        }
        while (lenB > lenA) {
            headB = headB.next; // B比A长,就让B先走
            lenB--;             // B向前走一步,长度减1
        }
        
        // **同步遍历,寻找交点**
        while (headA != null && headB != null) {
            if (headA == headB) {
                return headA; // 找到交点,返回该节点
            }
            headA = headA.next;
            headB = headB.next;
        }
        
        return null; // 没有交点,返回 null
    }
}

5. 详细代码解析(针对初学者)

第一部分:定义链表节点

class ListNode {
    int val;       // 存储数据
    ListNode next; // 指向下一个节点

    ListNode(int val) {
        this.val = val;
        this.next = null; // 初始时,没有指向下一个节点
    }
}
  • ListNode 是一个链表节点的类。
  • val 是节点存储的数据,例如 37
  • next 是指向下一个节点的指针。

第二部分:计算链表长度

public int getLength(ListNode head) {
    int length = 0;
    while (head != null) {
        length++;       // 遍历链表,每遇到一个节点,长度加1
        head = head.next; // 移动到下一个节点
    }
    return length;
}

这个方法的作用

  • 传入一个链表 head,计算它的长度。
  • 循环遍历,每访问一个节点,长度 +1,直到 null(链表末尾)。
  • 返回链表的总长度

第三部分:调整较长链表的起点

while (lenA > lenB) {
    headA = headA.next; // A比B长,A先走一步
    lenA--;             // 长度减少
}
while (lenB > lenA) {
    headB = headB.next; // B比A长,B先走一步
    lenB--;
}

为什么要调整?

  • 让两个链表的起点对齐。
  • 例如:
    • headA 长度 = 5
    • headB 长度 = 3
    • headA 先走 2 步,让它们对齐。

第四部分:同步遍历寻找交点

while (headA != null && headB != null) {
    if (headA == headB) {
        return headA; // 找到交点,返回节点
    }
    headA = headA.next;
    headB = headB.next;
}
return null; // 没有交点,返回 null

遍历方式

  1. 同时遍历两个链表
  2. 如果 headA == headB,说明找到了交点,直接返回。
  3. 如果遍历结束仍然没有相等的节点,返回 null(说明两个链表不相交)。

6. 代码运行示例

构造链表

public static void main(String[] args) {
    ListNode a1 = new ListNode(1);
    ListNode a2 = new ListNode(2);
    ListNode c1 = new ListNode(3);
    ListNode c2 = new ListNode(4);
    ListNode c3 = new ListNode(5);

    ListNode b1 = new ListNode(6);
    ListNode b2 = new ListNode(7);
    ListNode b3 = new ListNode(8);

    a1.next = a2;
    a2.next = c1;
    c1.next = c2;
    c2.next = c3;

    b1.next = b2;
    b2.next = b3;
    b3.next = c1;

    Solution solution = new Solution();
    ListNode intersection = solution.getIntersectionNode(a1, b1);
    
    if (intersection != null) {
        System.out.println("相交节点的值是:" + intersection.val);
    } else {
        System.out.println("两个链表没有相交");
    }
}

输出结果

相交节点的值是:3

7. 总结

  1. 计算两个链表的长度
  2. 调整较长的链表起点,让两个链表从相同位置开始遍历。
  3. 同步遍历寻找交点,找到就返回节点,没有交点就返回 null

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值