【LeetCode】【链表】剑指 Offer 52. 两个链表的第一个公共节点 思路解析和代码

剑指 Offer 52. 两个链表的第一个公共节点

题目链接

个人思路

思路

暴力O(mn)

双重循环求解,对比两个链中的每一个节点

栈-空间换时间O(m+n),空间(m+n)

由于第一个公共节点后面的所有节点均相等,因此可以从后往前遍历,直到找到最后一个相同的结点即为第一个公共节点,但由于单向链表无法逆序遍历,因此可以考虑使用栈辅助完成

双指针O(m+n)
  • 先遍历两个链表,得到两个链表的长度
  • 求出长度之差temp
  • 在较长的链表中,先遍历temp个结点,然后两个链表一同遍历,此时碰到的第一个相同的结点即为第一个公共节点

注意

  • 双指针在链表中的应用:双指针可以从固定两个指针之间的间距作为切入点来解决两个链表的第一个公共节点问题和链表中倒数第k个元素的问题

个人思路代码

暴力
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == NULL || headB == NULL){
            return NULL;
        }
        if(headA == headB){
            return headA;
        }
        ListNode *curA = headA, *curB = headB;
        ListNode *ans = NULL;
        bool flag = false;
        while(curA != NULL){
            if(flag == true)
                break;
            curB = headB;
            while(curB != NULL){
                if(curA == curB){
                    ans = curA;
                    flag = true;
                    break;
                }
                // cout << curA->val << " " << curB->val << endl;
                curB = curB->next;
            }
            curA = curA->next;
            // cout << curA->val << " " << curA->next << endl;
        }
        return ans;
    }
};

在这里插入图片描述

栈——以空间换时间
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    stack<ListNode*> sA;//时间换空间
    stack<ListNode*> sB;
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == NULL || headB == NULL){
            return NULL;
        }
        ListNode *cur = headA;
        while(cur != NULL){
            sA.push(cur);
            cur = cur->next;
        }
        cur = headB;
        while(cur != NULL){
            sB.push(cur);
            cur = cur->next;
        }
        ListNode *ans = NULL;
        if(sA.top() == sB.top()){
            ans = sA.top();//先记录最后一个相同的结点
        }else{
            return ans;
        }
        while(!sA.empty() && !sB.empty()){
            if(sA.top() != sB.top()){//寻找第一个不相同的结点
                break;
            }else{
                ans = sA.top();
            }
            sA.pop();
            sB.pop();
        }
        return ans;
    }
};

在这里插入图片描述

双指针
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *compareLists(ListNode *longer, ListNode *shorter, int temp){
        ListNode *curLonger = longer, *curShorter = shorter, *res = NULL;
        for(int i = 0; i < temp; ++i){
            curLonger = curLonger->next;
        }
        while(curLonger != NULL && curShorter != NULL){
            if(curLonger == curShorter){
                res = curLonger;
                break;
            }
            curLonger = curLonger->next;
            curShorter = curShorter->next;
        }
        return res;
    }
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == NULL || headB == NULL){
            return NULL;
        }
        int lenA = 0, lenB = 0;
        ListNode *cur = headA, *ans = NULL;
        while(cur != NULL){
            lenA++;
            cur = cur->next;
        }
        cur = headB;
        while(cur != NULL){
            lenB++;
            cur = cur->next;
        }
        // cout << lenA << " " << lenB << endl;
        if(lenA > lenB){
            ans = compareLists(headA, headB, lenA - lenB);
        }else{
            ans = compareLists(headB, headA, lenB - lenA);
        }
        return ans;
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值