微软亚洲研究院面试编程题之判断两个链表是否相交

给出两个单向链表的头指针,比如h1,h2。判断这两个链表是否相交。为了简化问题,我们假设两个链表均不带环。

问题扩展:
1.如果链表可能有环列?

2.如果需要求出两个链表相交的第一个节点列?

//链表结构体
typedef struct ListNode{
   int value;
   ListNode *next;

}ListNode;

//方法一:链表无环(判断两个单链表是否存在交点)
bool isCross(ListNode *p1,ListNode *p2)
{
   ListNode *x=p1;
   ListNode *y=p2;
   while(x->next!=NULL)
   {
       x=x->next;
   }
   while(y->next!=NULL)
   {
       y=y->next;
   }
   return (x==y);
}

//方法二:将其中一个链表中的尾节点与头节点联系起来,则该问题就转换为了求有环链表的第一个在环里的节点,如下图所示:
微软亚洲研究院面试编程题之判断两个链表是否相交_第1张图片

//判断链表是否有环
//设置两个指针(fast,slow),初始值都指向头,slow每次前进一步,fast每次前进两步。如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇

bool isLoop(ListNode *head)
{
   ListNode *slow=head;
   ListNode *fast=head;
   while(fast!=NULL&&fast->next!=NULL)
   {
       fast=fast->next->next;
       slow=slow->next; 
       if(fast==slow)
       {
           break;
       } 
   }
   if(fast==NULL||fast->next==NULL)
   {
       return false;
   }
   else
   {
        return true;
   }
}


//计算环的长度
int loopLength(ListNode *head)
{
   if(isLoop(head)==false)
   {
      return 0;
   }
   ListNode *fast=head;
   ListNode *slow=head;
   int len=0;
   bool begin=false;
   bool again=false;
   while(fast!=NULL&&fast->next!=NULL)
   {
      fast=fast->next->next;
      slow=slow->next;
      //超两圈后停止计数
      if(fast==slow && again==true)
      {
          break;
      }
      //超一圈后开始计数
      if(fast==slow && again==false)
      {
          begin=true;
          again=true;
      }
      if(begin==true)
      {
         ++len;
      }
   }
   return len;
}


/////////////////////////////////////////////////////1)当fast与slow相遇时,show肯定没有走完链表,而fast已经在还里走了n(n>= 1)圈。假设slow走了s步,那么fast走了2s步。fast的步数还等于s走的加上环里转的n圈,所以有:
2s = s + nr。因此,s = nr。
(2)设整个链表长为L,入口据相遇点X,起点到入口的距离为a。因为slow指针并没有走完一圈,所以:
a + x = s,带入第一步的结果,有:
a + x = nr = (n-1)r + r = (n-1)r + L - a;即:
a = (n-1)r + L -a -x;
这说明:从头结点到入口的距离,等于转了(n-1)圈以后,相遇点到入口的距离。因此,我们可以在链表头、相遇点各设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。

微软亚洲研究院面试编程题之判断两个链表是否相交_第2张图片

/////////////////////////////////////////////////////

//求出环的入口点
ListNode* findLoopEntrance(ListNode *head)
{
   ListNode *fast=head;
   ListNode *slow=head;
   while(fast!=NULL&&fast->next!=NULL)
   {
       fast=fast->next->next;
       slow=slow->next;
       if(fast==slow)
       {
           break;
       }
   }
   if(fast==NULL||fast->next==NULL)
   {
       return NULL;
   }
   slow=head;
   while(slow!=fast)
   {
      slow=slow->next;
      fast=fast->next;
   }
   return slow;
}

你可能感兴趣的:(算法,链表)