【面试题 02.07. 链表相交】——链表,双指针法,哈希表

面试题 02.07. 链表相交

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

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

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

示例 1:

示例 2:

示例 3:

提示:

  • listA 中节点数目为 m

  • listB 中节点数目为 n

  • 0 <= m, n <= 3 * 104

  • 1 <= Node.val <= 105

  • 0 <= skipA <= m

  • 0 <= skipB <= n

  • 如果 listAlistB 没有交点,intersectVal0

  • 如果 listAlistB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]

思考:

这道题在理解时有一个陷阱,它并不仅仅是寻找两个链表中数值相同的两个结点,而是寻找一个交点,交点后面的结点都一模一样。既然交点过后一模一样,那就代表着交点后面结点的数值以及长度都是相等的,对于一长一短两个链表,可以先进行预处理,让长链表中结点的指针移动到和短链表尾部对其的位置。

双指针法:

接着就可以比较剩下的子链表是否相同。如果不相同,同时向后移动指针。否则返回空指针。

class Solution {
 public:
     ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
         ListNode* curA = headA;
         ListNode* curB = headB;
         int lenA = 0, lenB = 0;
         while (curA != NULL) { // 求链表A的长度
             lenA++;
             curA = curA->next;
         }
         while (curB != NULL) { // 求链表B的长度
             lenB++;
             curB = curB->next;
         }
         curA = headA; //A链表指针
         curB = headB; //B链表指针
         // 让curA为最长链表的头,lenA为其长度
         if (lenB > lenA) {
             swap(lenA, lenB);
             swap(curA, curB);
         }
         // 求长度差
         int gap = lenA - lenB;
         // 让curA和curB在同一起点上(末尾位置对齐)
         while (gap--) {
             curA = curA->next;
         }
         // 遍历curA 和 curB,遇到相同则直接返回
         while (curA != NULL) {
             if (curA == curB) { //找到公共结点
                 return curA;
             }
             curA = curA->next;
             curB = curB->next;
         }
         return NULL;
     }
 };

代码参考:代码随想录

哈希表:

利用哈希表存储链表的结点,先遍历第一个链表,将第一个链表的每个结点加入到哈希集合中,然后遍历第二个链表,进行判断。

  • 如果当前节点不在哈希集合中,则继续遍历下一个节点;
  • 如果当前节点在哈希集合中,则后面的节点都在哈希集合中,即从当前节点开始的所有节点都在两个链表的相交部分,因此在链表headB 中遍历到的第一个在哈希集合中的节点就是两个链表相交的节点,返回该节点。
  • 如果链表headB中的所有节点都不在哈希集合中,则两个链表不相交,返回null。
class Solution {
 public:
    //哈希表
     ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
         unordered_set<ListNode*> visited;
         ListNode* temp = headA;
         while (temp != nullptr) {
             visited.insert(temp);
             temp = temp->next;
         }
         temp = headB;
         while (temp != nullptr) {
             if (visited.count(temp)) {
                 return temp;
             }
             temp = temp->next;
         }
         return nullptr;
     }
 };

代码参考:力扣官方题解


往期回顾:
LeetCode19. 删除链表的倒数第 N 个结点
LeetCode24. 两两交换链表中的节点
LeetCode206. 反转链表
LeetCode707.设计链表
LeetCode203.移除链表元素
LeetCode54. 螺旋矩阵
LeetCode59.螺旋矩阵II
LeetCode977.有序数组的平方
LeetCode844.比较含退格的字符串
LeetCode283.移动零
LeetCode27.移除元素
LeetCode26.删除有序数组中的重复项
LeetCode209.长度最小的子数组
LeetCode904. 水果成篮
LeetCode242.有效的字母异位词
LeetCode76.最小覆盖子串

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值