37-判断链表是否相交【找出第一个公共结点】

一、问题描述

编写一个程序来查找两个单独链接列表的交集开始的节点。
例如,以下两个链表:
A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗
B:     b1 → b2 → b3


开始在节点c1相交。
【提示】
如果两个链表完全没有交集,则返回null。
链接列表在函数返回后必须保留其原始结构。
您可能会认为整个链接结构中没有任何地方的循环。
您的代码应该最好在O(n)时间内运行,并只使用O(1)内存。

二、解题思路

思路一:一次重定向,再逐一比较 -- O(m+n)

1)将A重定向到B,得到一个新链表
2)将B重定向到A,得到一个等长的新链表
3)遍历这两个新链表,如果同时为空,说明并不会相交,
如果找到相同的元素,则该元素就是相交的元素

思路二:先补链表长度差,再逐一比较  --  O(m+n)

1)首先遍历两个链表得到他们的长度,就能知道哪个链表比较长,以及长链表比短链表多几个结点

2)第二次遍历时,在较长的链表上先走若干步,接着再同时在两个链表上遍历,找到第一个相同的结点就是他们第一个公共结点。

三、解题算法

思路一:一次重定向,再逐一比较

/*************************************************
Author:tmw
date:2018-4-14
*************************************************/
#include <stdio.h>
#include <stdlib.h>

typedef struct listnode
{
    int data;
    struct listnode* next;
}listnode;

listnode* getIntersectionNode( listnode* headA, listnode* headB )
{
    /**入口检查:当两者任意一个为空,则返回NULL**/
    if( headA == NULL || headB == NULL )
        return NULL;

    else
    {
        listnode* pa;
        listnode* pb;
        pa = headA;
        pb = headB;
        int flagA = 0;
        int flagB = 0;

        while( pa && pb ) /**约定链表没有头指针,首位即存有值**/
        {
            if( pa->data == pb->data )
                return pa;

            pa = pa->next;
            pb = pb->next;

            /**将A重定向到B,得到一个新链表**/
            /**flagA用于只重定向一次,避免程序重复重定向而死循环了**/
            if( pa == NULL && flagA == 0 )
            {
                pa = headB;
                flagA = 1;
            }

            /**将B重定向到A,得到一个等长的新链表**/
            /**flagB作用同flagA**/
            if( pb == NULL && flagB == 0 )
            {
                pb = headA;
                flagB = 1;
            }
        }
        /**还没找到,则说明两个链表没有交点**/
        return NULL;
    }
    return NULL;
}

思路二:先补链表长度差,再逐一比较  --  O(m+n)

/**
* 解法二:先补链表长度差,再逐一比较
**/
int listNodeLength( listNode* head )
{
    int len = 0;
    listNode* p = head;
    while(p)
    {
        len++;
        p = p->next;
    }
    return len;
}
listNode* findFistCommomNodeMethod1( listNode* head1, listNode* head2 )
{
    if( head1==NULL || head2==NULL ) return NULL;
    int len1 = listNodeLength(head1);
    int len2 = listNodeLength(head2);
    int gap = len1 - len2;
    //保证pLong始终指向的是长度长一点的链表,pShort指向的是长度短一点的链表
    listNode* pLong = head1;
    listNode* pShort = head2;
    if( len1 < len2 )
    {
        pLong = head2;
        pShort = head1;
        gap = len2 - len1;
    }

    //长链表先走
    int i;
    for( i=0; i<gap; i++ )
        pLong = pLong->next;

    //此时长链表和短链表的同时开始挪动
    while( pLong != NULL && pShort != NULL && pLong->data != pShort->data )
    {
        pLong = pLong->next;
        pShort = pShort->next;
    }
    return pLong;
}

 

梦想还是要有的,万一实现了呢~~~ヾ(◍°∇°◍)ノ゙~~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值