编程导航算法通关村第1关 _ 两个链表的第一个公共子结点

1 解决两个链表的第一个公共子结点

本文主要看一道LeetCode经典的链表题目。剑指offer 52题 :输入两个链表,找出它们的第一个公共节点。例如下面的两个链表:
image.png
两个链表的头结点都是已知的,相交后成为一个单链表,但是相交的位置未知,并且相交之前的结点数也是未知的,请设计算法找到两个链表的合并点。

1.1 分析

  • 没有思路时的解题方法

将常用的数据结构和常用算法思想想一遍,看看哪些能解决问题。
常用的数据结构有数组、链表、队、栈、Hash、集合、树、堆。常用的算法思想有查找、排序、双指针、递归、迭代、分治、贪心、回溯和动态规划等等。

1.2 拼接两个字符串

尝试把上面的链表分别拼接成AB和BA,可以得到下图结果。有意思的是,从最后的c1开始,两个链表开始一样了,c1就是要找的公共结点,所以可以通过拼接的方式寻找交点。
image.png
那要怎么做呢?分别遍历AB和BA进行比较,这样还要重新建立新的链表浪费空间,为进一步优化,可以在每个链表访问完之后,调整一下链表的表头继续遍历即可。
C语言实现

struct ListNode *getCommNode(struct ListNode *headA, struct ListNode *headB)
{
    if (headA == NULL || headB == NULL)
    {
        return NULL;
    }
    ListNode *p1 = headA;
    ListNode *p2 = headB;

    while (p1 != p2)
    {
        p1 = p1->next;
        p2 = p2->next;

        if (p1 != p2) // 防止A和B无交集时陷入死循环
        {
            if (p1 == NULL)
            {
                p1 = headB;
            }
            if (p2 == NULL)
            {
                p2 = headA;
            }
        }
    }
    return p1;
}

1.3 差和双指针

假如两个链表一定存在公共结点,假设链表A的长度为L1,链表B的长度为L2,那么,| L1-L2 |就是两个的差值。遍历的时候,长的链表先走| L1-L2 |,然后两个链表同时向前走,结点一样的时候就是公共结点。
image.png 那要怎么做呢,首先遍历第一遍获取两个链表长度;然后,计算两个链表的差值,让长的先走差值的步长;最后再一一进行比较,找到相同的结点。
C语言实现

struct ListNode *getCommList(struct ListNode *headA , struct ListNode *headB)
{
    struct ListNode *p1 = headA;
    struct ListNode *p2 = headB;
    int len1 = 0;
    int len2 = 0;
    int lenSub = 0;

    if(headA == NULL || headB == NULL)
    {
        return NULL;
    }
    while (p1)
    {
        len1++;
        p1 = p1->next;
    }

    while (p2)
    {
        len2++;
        p2 = p2->next;
    }
    p1 = headA;
    p2 = headB;
    lenSub = len1 > len2 ? len1 - len2 : len2 - len1;
    if(len1>len2)
    {
        int count1 = 0;
        while( count1 != lenSub)
        {
            p1 = p1->next;
            count1++;
        }
    }
    if(len1<len2)
    {
        int count2 = 0;
        while(count2 != lenSub)
        {
            p2 = p2->next;
            count2++;
        } 
    }

    while (p1!=p2)
    {
        p1 = p1->next;
        p2 = p2->next;
    }
    return p1;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值