剑指offer:两个链表的第一个公共结点

1. 题目描述

输入两个链表,找出它们的第一个公共结点。

2. 题目分析

    首先我们需要理解题目的含义,如果两个链表有公共结点,那么由于每个结点都只有一个指向,因此从公共结点开始,两个链表的后续结点都是重合的。两个链表呈横置的Y型。


        然后开始考虑此题的解法:

(1)暴力解法

    从第一个链表的头结点开始遍历,对于第一个链表的每一个结点,都遍历第二个链表进行比较,直到找到相同的结点。

    下面是第一种想法的解法,本来以为没办法AC的,没想到直接AC了,这就很尴尬了。然鹅,不管怎样,面试官是不可能满意这种解法的,因此,我们必须要引入下面两种解法。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if(pHead1==NULL||pHead2==NULL)
            return NULL;
        ListNode *tmp1 = pHead1;
	    ListNode *tmp2 = pHead2;
	    while (tmp1 != NULL)
	    {
		    while (tmp2 != NULL)
		    {
			    if (tmp1 == tmp2)
			    {
				    return tmp1;
			    }
			    tmp2 = tmp2->next;
		    }
		    tmp2 = pHead2;
		    tmp1 = tmp1->next;
	    }
        return NULL;
    }
};

(2)先进后出---栈

    正是因为相交的两个链表呈横置的Y型,而两个链表的长度又一定相同,因此,如果从头到尾依次比较各结点,并不能同时到达相交的结点;因此,我们想到从后往前比较结点,那么最后一对相同的结点,就是我们要找的结点。

    为了实现这种方法,我们想到了栈的特性,因此我们需要建立两个栈,长度分别为m,和n,第一步先把两个链表中的数据全部放入栈中,第二步,再依次比较两个栈的栈顶元素,直到找到不同的那个结点为止。

    实现代码如下:

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        
        if(pHead1==NULL||pHead2==NULL)
            return NULL;
        ListNode *result = NULL;
        stack<ListNode*> stack1;
	    stack<ListNode*> stack2;
	    ListNode *p1 = pHead1;
	    ListNode *p2 = pHead2;
	    while (p1 != NULL)
	    {
		    stack1.push(p1);
		    p1 = p1->next;
	    }
	    while (p2 != NULL)
	    {
		    stack2.push(p2);
		    p2 = p2->next;
	    }
	    while (!stack1.empty() && !stack2.empty() && stack1.top() == stack2.top())
	    {
		    result = stack1.top();
		    stack1.pop();
		    stack2.pop();
        }
        return result;
    }
};

    这种解法的时间复杂度是O(m+n),空间复杂度也是m+n,通过牺牲空间换取时间效率,看似效率有很大的提高,但这种方法面试官仍然不会满意的(事儿多......),因此我们需要再考虑能否不牺牲空间,仍然可以获得较好的时间效率。

(3)求长度之差

    在第二种方法中,我们之所以要用到栈,是因为两个链表的长度不一致,我们没有办法同时达到相交的结点。因此我们可以先求出两个链表的长度,算出两个链表的长度之差,然后较长的链表可以先前行delterx步,使得两个链表可以同时达到相交的结点;然后再依次比较两个链表,直到找到相同的结点为止。

    代码实现如下:

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        
        if(pHead1==NULL||pHead2==NULL)
            return NULL;
        ListNode *tmp1 = pHead1;
        ListNode *tmp2 = pHead2;
        int length1 = 0;
        int length2 = 0;
        while(tmp1!=NULL)
        {
            length1++;
            tmp1 = tmp1->next;
        }
        while(tmp2!=NULL)
        {
            length2++;
            tmp2 = tmp2->next;
        }
        tmp1 = pHead1;
        tmp2 = pHead2;
        for(int i = 0; i < abs(length1-length2); i++)
        {
            tmp1 = tmp1->next;
        }
        while(tmp1!=NULL && tmp2!=NULL)
        {
            if(tmp1 == tmp2)
            {
                return tmp1;
            }
            tmp1 = tmp1->next;
            tmp2 = tmp2->next;
        }
        
        return NULL;
    }
};

    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值