线性复杂度查找链表的公共节点

题目详情:输入两个链表,找出它们的第一个公共结点。
思路

  • 1,由于从公共节点开始之后都是公共节点,也就是说不管两个链的长度是否一样,反过来的公共长度一定一样,于是用两个栈来从后往前匹配,找到最后一个公共节点即为原链的第一个公共节点。
  • 2,和思路一很类似,先让两个开始匹配的指针水平线相同,也就是长的那个要走到与短的那个链有相同长度的位置,之后就从前往后匹配。之所以这样子做是因为: 假 设 k 为 公 共 长 度 , t 1 为 链 1 的 非 公 共 长 度 , t 2 为 链 2 的 非 公 共 长 度 , 那 么 s 1 = t 1 + k , s 2 = t 2 + k , 则 长 的 那 个 移 动 的 偏 移 量 = ∣ s 1 − s 2 ∣ = ∣ t 1 − t 2 ∣ , 说 明 不 会 动 到 公 共 部 分 k , 所 以 在 这 个 位 置 往 后 找 不 影 响 结 果 。 假设k为公共长度,t1为链1的非公共长度,t2为链2的非公共长度,那么s1=t1+k,s2=t2+k,则长的那个移动的偏移量=|s1-s2|=|t1-t2|,说明不会动到公共部分k,所以在这个位置往后找不影响结果。 k,t11t22s1=t1+k,s2=t2+k,=s1s2=t1t2,k
  • 3,假设有公共部分,那么公共部分一定在最尾部,把链1链2分别叠加到一块,则有 s 1 = s 1 + s 2 , s 2 = s 2 + s 1 , 处 理 后 s 1 = s 2 s1=s1+s2,s2=s2+s1,处理后s1=s2 s1=s1+s2,s2=s2+s1,s1=s2,然后直接从前往后匹配处理后的串,最终一定回匹配到后面对齐的公共部分。

以上三个思路的复杂度都是 O ( n + m ) O(n+m) O(n+m)关键都是发现尾部从第一个公共节点开始之后都相等这个特点,这个方法同样可以拓展到多个链表找公共节点

Code

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        //法一:
        //4ms
        stack<ListNode*> stk1, stk2;
        ListNode* pub = NULL;
        while (!stk1.empty()) stk1.pop();
        while (!stk2.empty()) stk2.pop();
        while (pHead1) {
            stk1.push(pHead1);
            pHead1=pHead1->next;
        }
        while (pHead2) {
            stk2.push(pHead2);
            pHead2=pHead2->next;
        }
        while (!stk1.empty() && !stk2.empty()) {
          if (stk1.top() != stk2.top()) break;
          pub = stk1.top();
          stk1.pop();
          stk2.pop();
        }
        while (!stk1.empty()) stk1.pop();
        while (!stk2.empty()) stk2.pop();
        return pub;

        //法二:
        //3ms
        int len1 = 0, len2 = 0, k;
        ListNode* p = pHead1;
        ListNode* q = pHead2;
        while (p) len1++, p = p->next;
        while (q) len2++, q = q->next;
        if (len1 > len2) {
            k = len1 - len2;
            while (k--) pHead1 = pHead1->next; 
        } else if (len2 > len1) {
            k = len2 - len1;
            while (k--) pHead2 = pHead2->next; 
        }
        while (pHead1) {
            if (pHead1 == pHead2) break;
            pHead1 = pHead1->next;
            pHead2 = pHead2->next;
        }
        return pHead1;

        //法三:
        //3ms
        ListNode* p = pHead1;
        ListNode* q = pHead2;
        while (p != q) {
            p = p ? p->next : pHead2;
            q = q ? q->next : pHead1;
        }
        return p;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小胡同的诗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值