一、题目

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:

160. 相交链表-每日一题 - 图1
题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

点击查看原题

二、思路

1)获取长度+双指针

观察题目给出的链表,如果进行两个指针移动,怎么知道另一个指针访问过?
由于相交链表的最后一段是共同拥有的,所以从相交节点开始到最末端的长度相等(也就是图中c1、c2、c3),可以采用以下思路:

1、获取A链表长度和B链表长度 2、将A和B的遍历指针对齐(比如B链表需要移动到b2位置),确保到相交节点的位置距离相等 3、同时移动两个遍历指针,判断两个指针指向对象是否是同一个

还有不相交的情况需要考虑,如果两个指针指向了末尾节点都不相等,它们会继续向下指向null,这个判断是相等的,满足题目要求的返回值。

2)哈希表

如果需要快速解题,最简单的思路就是使用哈希表记录A链表的所有节点,然后遍历B链表查询是否存在该节点。
逻辑清晰,代码量少,适合先验证逻辑。但耗时较多。

三、代码

1)获取长度+双指针

  1. public class Solution {
  2. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  3. int lenA = getLength(headA);
  4. int lenB = getLength(headB);
  5. int diff = lenA - lenB;
  6. if (diff > 0) {
  7. while (diff-- > 0) {
  8. headA = headA.next;
  9. }
  10. } else {
  11. while (diff++ < 0) {
  12. headB = headB.next;
  13. }
  14. }
  15. while (headA != headB) {
  16. headA = headA.next;
  17. headB = headB.next;
  18. }
  19. return headA;
  20. }
  21. private int getLength(ListNode head) {
  22. int len = 0;
  23. while (head != null) {
  24. len++;
  25. head = head.next;
  26. }
  27. return len;
  28. }
  29. }

时间复杂度为O(max(lenA, lenB)),空间复杂度为O(1)。

2)哈希表

  1. public class Solution {
  2. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  3. Set<ListNode> set = new HashSet();
  4. while (headA != null) {
  5. set.add(headA);
  6. headA = headA.next;
  7. }
  8. while (headB != null) {
  9. if (set.contains(headB)) {
  10. return headB;
  11. }
  12. headB = headB.next;
  13. }
  14. return headB;
  15. }
  16. }

时间复杂度为O(lenB*log(lenA)),空间复杂度为O(lenA)。