剑指Offer--037-两个链表的第一个公共结点

链接


牛客OJ:两个链表的第一个公共结点

九度OJ:http://ac.jobdu.com/problem.php?pid=1505

GitHub代码: 037-两个链表的第一个公共结点

CSDN题解:剑指Offer–037-两个链表的第一个公共结点

牛客OJ 九度OJ CSDN题解 GitHub代码
037-两个链表的第一个公共结点 1505-两个链表的第一个公共结点 剑指Offer–037-两个链表的第一个公共结点 037-两个链表的第一个公共结点

题意



题目描述

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

暴力方法



最简单直接的方法就是,对于第一个链表的每个节点,我们依次判断其是不是第二条链表的公共结点

#include <iostream>

using namespace std;

//  调试开关
#define __tmain main

#ifdef __tmain

#define debug cout

#else

#define debug 0 && cout

#endif // __tmain

#ifdef __tmain

struct ListNode
{
public :
    int val;
    struct ListNode *next;

};
#endif

class Solution
{
public:
    ListNode* FindFirstCommonNode(ListNode *leftHead, ListNode *rightHead)
    {
        ListNode *left = NULL;
        ListNode *right = NULL;

        //  循环第一个链表的每个结点
        for(left = leftHead;
            left != NULL;
            left = left->next)
        {
            debug <<endl <<left->val <<" : ";

            //  依次判断其在不在第二条链表中
            for(right = rightHead;
                right != NULL;
                right = right->next)
            {
                debug <<right->val <<", ";
                if(left == right)
                {
                    break;
                }
            }
            if(left == right)
            {
                break;
            }
        }

        return left;
    }
};

int __tmain( )
{
    ListNode common[2];
    common[0].val = 6;
    common[0].next = &common[1];
    common[1].val = 7;
    common[1].next = NULL;

    ListNode left[3];
    left[0].val = 1;
    left[0].next = &left[1];
    left[1].val = 2;
    left[1].next = &left[2];
    left[2].val = 3;
    left[2].next = &common[0];

    ListNode right[2];
    right[0].val = 4;
    right[0].next = &right[1];
    right[1].val = 5;
    right[1].next = &common[0];

    Solution solu;
    ListNode *node = solu.FindFirstCommonNode(left, right);
    while(node != NULL)
    {
        debug <<node->val <<" ";
        node = node->next;
    }
    debug <<endl;

    return 0;
}

右对齐两个链表



如果两个链表有公共节点,则它们的形状必然是一个Y字形。

长链表先走,实现右对齐



先假设这两个链表的长度相等,则我们可以同步遍历这两个链表,找到公共节点。现在有两个链表,我们可以先分别求齐长度得其差n,然后遍历长的那个链表n个节点,然后同步遍历这两个链表即可。

class Solution
{
public:
    ListNode* FindFirstCommonNode(ListNode *leftHead, ListNode *rightHead)
    {
        ListNode *left = leftHead;
        ListNode *right = rightHead;
        int leftLength = 0;
        int rightLength = 0;

        ///  首先计算两个链表的长度
        leftLength = GetListLength(left);
        rightLength = GetListLength(right);

        ///  对齐两个链表
        int length = 0;

        if(leftLength < rightLength)
        {
            // 右链表长
            length = rightLength - leftLength;
            while(right != NULL && length > 0)
            {
                right = right->next;
                length--;
            }
        }
        else
        {
            // 左链表长
            length = leftLength - rightLength;
            while(left != NULL && length > 0)
            {
                left = left->next;
                length--;
            }
        }

        //  两个指针同步移动即可找到共同的结点
        while(left != NULL && right != NULL)
        {
            if(left == right)
            {
                break;
            }
            left = left->next;
            right = right->next;
        }

        return ((left == right) ? left : NULL);
    }

    int GetListLength(ListNode *head)
    {
        ListNode *node = head;
        int length = 0;
        while(node != NULL)
        {
            length++;
            node = node->next;
        }       

        return length;
    }
};

将两个链表拼接起来实现右对齐



前面那个思路中,长的链表先走一个长度差,从而保证两个链表是右对齐的,但是这种方式,我们需要多次扫面链表,因为链表必须通过扫描才能获取其长度

但是有没有不需要多次扫描就可将两个链表对齐的方法呢。

我们可以将两个链表拼接在一起来实现其

left : left->right

>

right : right->left

这样一来我们的链表就成了长度为M+N的两个链表,而公共部分都在最后,而且是对齐的


class Solution
{
public:
    ListNode* FindFirstCommonNode(ListNode *leftHead, ListNode *rightHead)
    {
        ListNode *left= leftHead;
        ListNode *right = rightHead;

        debug <<(left == NULL ? -1 : left->val) <<", ";
        debug <<(right == NULL ? -1 : right->val) <<endl;

        while(left != right)
        {

            left = (left == NULL ? rightHead : left->next);
            right = (right == NULL ? leftHead : right->next);
            debug <<(left == NULL ? -1 : left->val) <<", ";
            debug <<(right == NULL ? -1 : right->val) <<endl;

        }
        return left;
    }
};

栈的后进先出实现右对齐



由于栈是后进先出的,因此我们将两个链表分别入栈,那么栈顶的元素一定是最后一个元素。从而两个链表是右对齐的,两个栈同步弹出,当两个栈顶的节点不相同时候,即是开始合并的前一个节点

class Solution
{
public:
    ListNode* FindFirstCommonNode(ListNode *leftHead, ListNode *rightHead)
    {
        ListNode *left = leftHead;
        ListNode *right = rightHead;

        stack<ListNode *> leftStack;
        stack<ListNode *> rightStack;

        /// 结点依次入栈
        while(left != NULL)
        {
            //debug <<left->val <<endl;
            leftStack.push(left);
            left = left->next;
        }

        while(right != NULL)
        {
            //debug <<right->val <<endl;
            rightStack.push(right);
            right = right->next;
        }

        ///  开始同步弹出元素
        while(leftStack.empty( ) != true
           && rightStack.empty( ) != true)
        {
            left = leftStack.top( );
            right = rightStack.top( );

            debug <<left->val <<", " <<right->val <<endl;

            ///  不相同的元素就是合并的前一个结点
            if(left != right)
            {
                break;
            }
            leftStack.pop( );
            rightStack.pop( );
        }

        ///  不相同元素的下一个结点就是共同结点
        if(left != right)
        {
            return left->next;
        }
        else
        {
            return NULL;
        }
    }
};

利用高效的数据结构实现查找结点


当然还有其他思路,我们可以使用一个查找效率高的数据结构,比如hash或者map

>

先将第一个链表插入,然后因此判断第二个链表的节点在不在map中,即可查找到第一个共同结点

利用unordered_map,这个模板类是基于hash表实现的,速度与map、hashmap相比较快

class Solution
{
public:
    ListNode* FindFirstCommonNode(ListNode *leftHead, ListNode *rightHead)
    {
        unordered_map<ListNode*, bool> umap;

        ListNode* left = leftHead;
        while (left != NULL)
        {
            umap.insert(make_pair(left, 1 ));
            left = left->next;
        }

        ListNode* right = rightHead;
        while (right)
        {
            if (umap.count(right)>0)
            {
                return right;
            }
            right = right->next;
        }
        return NULL;
    }
};
时间: 2024-10-13 13:38:42

剑指Offer--037-两个链表的第一个公共结点的相关文章

剑指offer (37) 两个链表的第一个公共结点

题目:输入两个链表,找出它们的第一个公共结点 如果两个链表有公共结点,那么公共结点一定出现在两个链表的尾部 如果两链表长度不相等,那么达到公共结点的步数就不一致,如何确保 两个链表从头开始遍历,同步达到公共结点? 这是关键所在 如果两链表长度相同,那么就可以同步达到了? 由此,我们就需要 让两个链表长度"相等" 我们假设 两链表长度分别为m和n,且m > n, 那么我们可以在较长链表中 先走 m - n 步,然后 两个链表游标同步走,如果有公共结点,那么就一定同时达到 ListN

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

转载请注明出处:http://blog.csdn.net/ns_code/article/details/26097395 简单题,剑指offer上的第37题,九度OJ上AC. 题目描述: 输入两个链表,找出它们的第一个公共结点. 输入: 输入可能包含多个测试样例.对于每个测试案例,输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的两个链表的元素的个数.接下来的两行,第一行为第一个链表的所有元素,中间用空格隔开.第二行为第二个链表的所有元素,中间用空格隔开. 输出: 对应

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

题目描述输入两个链表,找出它们的第一个公共结点. # -*- coding: utf-8 -*- # @Time : 2019-07-12 22:20 # @Author : Jayce Wong # @ProjectName : job # @FileName : findFirstCommonNode.py # @Blog : https://blog.51cto.com/jayce1111 # @Github : https://github.com/SysuJayce class Lis

两个链表的第一个公共结点(剑指offer)+链表

两个链表的第一个公共结点 参与人数:1171时间限制:1秒空间限制:32768K 通过比例:31.25% 最佳记录:0 ms|0K(来自  running) 题目描述 输入两个链表,找出它们的第一个公共结点. 链接:http://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

两个链表的第一个公共结点-剑指Offer

两个链表的第一个公共结点 题目描述 输入两个链表,找出它们的第一个公共结点. 思路 若用暴力比较,一个个的节点比较,时间复杂度为O(n2),不可取 根据题意,两个链表若有公共节点,最终要连起来,像一个Y形,所以我们从后往前遍历,但是单向链表只能从前往后,所以这符合“先进后出”,可以用两个辅助栈 也可以不用辅助栈,我们先将两个链表遍历一遍,获取长度大小,然后从长的先开始遍历,到达相等长度后同时开始遍历,直到遍历到相等的节点 这个问题可以类比到求二叉树中两个叶结点的最低公共祖先的问题 代码 /* p

编程算法 - 两个链表的第一个公共结点 代码(C)

两个链表的第一个公共结点 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入两个链表, 找出它们的第一个公共结点. 计算链表的长度, 然后移动较长链表的指针, 使其到相同结点的距离的相同, 再同时移动两个链表的指针, 找到相同元素. 时间复杂度: O(n) 代码: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */ /*eclipse cdt, gcc 4.8.1*/ #i

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

输入两个链表,找出它们的第一个公共结点. import java.util.*; public class Solution { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { ListNode current1 = pHead1; ListNode current2 = pHead2; HashMap<ListNode,Integer> hashMap = new HashMap<ListN

剑指offer(四十四)之两个链表的第一个公共结点

题目描述 输入两个链表,找出它们的第一个公共结点. 思路分析:将其中一个链表结点,存进HashMap中,将利用ContainsKey()进行判断是否有公共结点 代码1: <span style="color:#6600cc;">import java.util.*; public class Solution { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { ListNode

剑指offer 36.时间空间效率的平衡 两个链表的第一个公共结点

题目描述 输入两个链表,找出它们的第一个公共结点. 解题思路 如果存在共同节点的话,那么从该节点,两个链表之后的元素都是相同的. 也就是说两个链表从尾部往前到某个点,节点都是一样的. 我们可以用两个栈分别来装这两条链表.一个一个比较出来的值. 找到第一个相同的节点. 代码如下 public class FindFirstCommonNode { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { if (

剑指offer系列——36.两个链表的第一个公共结点

Q:输入两个链表,找出它们的第一个公共结点.(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的) T:这个题的意思是两个链表要么有公共结点,要么没有公共结点,不存在相交的情况. A: 1.传统做法:长的先走,直到和短的相同长度,然后两个一起走,直至相等. ListNode *FindFirstCommonNode(ListNode *pHead1, ListNode *pHead2) { if (pHead1 == nullptr || pHead2 ==