C/C++面试:39---两条相交的单向链表,如何求它们的第一个公共节点?

一、问题描述

  • 现在有两条单向链表,如何判断它们是否相交,以及相交时的第一个公共节点在哪?

二、解决方案

  • 先判断它们是否相交:如果它们是相交的,那么必然尾节点相同。因此,可以遍历两个单链表,一直遍历到尾节点,然后判断它们的尾节点指针是否相同,如果相同则可以确定它们相交
  • 如果相交,再找出两个单链表的第一个公共节点:
    • 获取两个单链表的长度,设为LA和LB
    • 如果LA>LB,则单链表A从距头结点距离为LA-LB的那个节点开始遍历,LB直接从头结点开始遍历,当遍历到两个节点的指针都相同时,那么这两个单链表相交
    • 如果LB>LA,则单链表B从距头结点距离为LB-LA的那个节点开始遍历,LA直接从头结点开始遍历,当遍历到两个节点的指针都相同时,那么这两个单链表相交

三、编码实现

  • 此处我们假设单链表的头结点也作为实际节点使用
/**
 * @description: 判断list1和list2是否相交, 如果相交返回一个公共节点的指针
 * @param :
       list1: 链表1 
       list2: 链表2
 * @return: 
       不想交, 没有公共节点: NULL 
       相交: 返回第一个公共节点的指针
 * @author: Dongshao
 */
Node* firstCommonNode(Node *list1, Node *list2)
{
    Node *temp1 = list1;
    Node *temp2 = list2;

    size_t list1Size = 0;
    size_t list2Size = 0;

    // 先判断两个链表是否相交: 
    //    判断两个链表的尾节点是否相同即可
    //    再遍历的时候同时记录两个链表的长度
    for(temp1; temp1->_pnext != NULL; temp1 = temp1->_pnext)
        ++list1Size;
    ++list1Size;
    for(temp2; temp2->_pnext != NULL; temp2 = temp2->_pnext)
        ++list2Size;
    ++list2Size;
    // 如果尾节点不相同, 那么两个单链表不相交, 返回NULL
    if(temp1 != temp2)
        return NULL;

    // 根据哪个链表长, 设定遍历起点
    // 如果list1 > list2, 则temp1指向距头结点长度为(list1-list2)的节点, temp2直接指向头结点
    if(list1Size > list2Size) 
    {
        temp1 = list1;
        for(int i = 0; i < (list1Size - list2Size); ++i)
            temp1 = temp1->_pnext;
        temp2  = list2;
    }
    // 如果list1 < list2
    else if(list1Size < list2Size)
    {
        temp2 = list2;
        for(int i = 0; i < (list2Size - list1Size); ++i)
            temp2 = temp2->_pnext;
        temp1 = list1;
    }
    else
    {
        temp1 = list1;
        temp2 = list2;
    }
    
    // 然后开始遍历, 如果遍历到一个指针相同的节点, 那么这个就是第一个相交的节点, 直接返回即可
    while(temp1 != temp2)
    {
        temp1 = temp1->_pnext;
        temp2 = temp2->_pnext;
    }

    return temp1;
}

四、测试代码

#include <iostream>

using namespace std;

typedef struct node
{
    struct node *_pnext;
    int data;
} Node;


/**
 * @description: 判断list1和list2是否相交, 如果相交返回一个公共节点的指针
 * @param :
       list1: 链表1 
       list2: 链表2
 * @return: 
       不想交, 没有公共节点: NULL 
       相交: 返回第一个公共节点的指针
 * @author: Dongshao
 */
Node* firstCommonNode(Node *list1, Node *list2)
{
    Node *temp1 = list1;
    Node *temp2 = list2;

    size_t list1Size = 0;
    size_t list2Size = 0;

    // 先判断两个链表是否相交: 
    //    判断两个链表的尾节点是否相同即可
    //    再遍历的时候同时记录两个链表的长度
    for(temp1; temp1->_pnext != NULL; temp1 = temp1->_pnext)
        ++list1Size;
    ++list1Size;
    for(temp2; temp2->_pnext != NULL; temp2 = temp2->_pnext)
        ++list2Size;
    ++list2Size;
    // 如果尾节点不相同, 那么两个单链表不相交, 返回NULL
    if(temp1 != temp2)
        return NULL;

    // 根据哪个链表长, 设定遍历起点
    // 如果list1 > list2, 则temp1指向距头结点长度为(list1-list2)的节点, temp2直接指向头结点
    if(list1Size > list2Size) 
    {
        temp1 = list1;
        for(int i = 0; i < (list1Size - list2Size); ++i)
            temp1 = temp1->_pnext;
        temp2  = list2;
    }
    // 如果list1 < list2
    else if(list1Size < list2Size)
    {
        temp2 = list2;
        for(int i = 0; i < (list2Size - list1Size); ++i)
            temp2 = temp2->_pnext;
        temp1 = list1;
    }
    else
    {
        temp1 = list1;
        temp2 = list2;
    }
    
    // 然后开始遍历, 如果遍历到一个指针相同的节点, 那么这个就是第一个相交的节点, 直接返回即可
    while(temp1 != temp2)
    {
        temp1 = temp1->_pnext;
        temp2 = temp2->_pnext;
    }

    return temp1;
}


int main()
{
    // 构建LA的前半部分
    Node *anode1 = (Node*)malloc(sizeof(Node));
    Node *anode2 = (Node*)malloc(sizeof(Node));
    Node *anode3 = (Node*)malloc(sizeof(Node));
    anode1->data = 1;
    anode2->data = 7;
    anode3->data = 4;
    anode1->_pnext = anode2;
    anode2->_pnext = anode3;

    // 构建LB的前半部分
    Node *bnode1 = (Node*)malloc(sizeof(Node));
    Node *bnode2 = (Node*)malloc(sizeof(Node));
    bnode1->data = 1;
    bnode2->data = 7;
    bnode1->_pnext = bnode2;

    // 构建两个公共节点
    Node *commonNode1 = (Node*)malloc(sizeof(Node));
    Node *commonNode2 = (Node*)malloc(sizeof(Node));
    commonNode1->data = 8;
    commonNode2->data = 10;
    commonNode2->_pnext = NULL;
    commonNode1->_pnext = commonNode2;

    // 将公共节点拼接到LA和LB的后面
    anode3->_pnext = commonNode1;
    bnode2->_pnext = commonNode1;

    // 寻找公共节点, 并打印值
    Node *commonNode = firstCommonNode(anode1, bnode1);
    std::cout << "firstCommonNode data: " << commonNode->data << std::endl;

    return 0;
}
  • 测试的两条链表如下: 

  • 运行效果如下:

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/107753938