Interview----判断两个链表是否相交?

题目描述:

判断两个单链表是否相交?假设链表没有环。

假如链表有环呢?


 1.  假如没有环

那么如果两个链表相交的话,必然最后的节点一定是同一个节点。所以只需要各自扫描一遍链表,找到最后一个节点,比较是否相同即可。

O ( M + N)

// version 1
// test whether two lists are intersected
// assume each list has no circle
bool IsIntersectedNoCircle(ListNode *lhs, ListNode *rhs)
{
  if(lhs == NULL || rhs == NULL)
    return false;

  ListNode *tail1(lhs);
  for(; tail1->next; tail1 = tail1->next);

  ListNode *tail2(lhs);
  for(; tail2->next; tail2 = tail2->next);

  return tail1 == tail2;
}



2. 可能有环

首先,如何判断是否有环?

采用快慢指针,一个指针一次走两步,一个指针一次走一步,如果链表有环的话,必然最后慢指针会赶上快指针。

复杂度同样是 O ( M + N)。

如果还要求求出 进入环的那个节点: 可以用两个指针,一个从链表head 出发,另一个从刚刚快慢指针的相遇点出发,速度相同。

可以证明,两指针必定在入口处第一次相遇。

// test whether list has a circle
// if true, return the enter node
// if not,  return NULL
ListNode* HasCircle(ListNode *list)
{
  if(list == NULL || list->next == NULL) 
    return NULL;

  // fast/slow pointer method
  // if circled, slow pointer will catch up with fast one
  ListNode *fast(list), *slow(list);

  while(fast)
  {
    fast = fast->next;
	if(fast == NULL) return NULL;
	fast = fast->next;
	slow = slow->next;

	if(fast == slow)
	  break;
  }
  assert(fast == NULL || slow == fast); 

  if(fast == NULL) 
    return NULL;

  // list definitely has a circle
  // find the enter node
  // fast and enter will meet at the enter node
  ListNode *enter(list);

  while(enter != fast)
  {
    enter = enter->next;
	fast = fast->next;
  }

  return enter;
}


根据是否有环,可以分为以下三个 case:

   case 1: 都没有环:已经分析

   case 2: 都有环: 注意到如果相交,这两个环必定是一模一样的。所以,只要判断是否有一个节点在另一个环中即可。

   case 3: 一个有环,一个没有环: 一定不相交


// version 2
// assume lists may have a circle inside 
bool IsIntersectedCircle(ListNode *lhs, ListNode *rhs)
{
  ListNode *enter1(NULL), *enter2(NULL);

  enter1 = HasCircle(lhs);
  enter2 = HasCircle(rhs);

  // case 1: both lists have no circles
  if(enter1 == NULL && enter2 == NULL)
  {
    return IsIntersectedNoCircle(lhs, rhs);
  }
  // case 2: each have a circle
  else if(enter1 && enter2)
  { 
    ListNode *node(enter1->next); 

	while(node != enter1 && node != enter2){
	  node = node->next;
	}
	return node == enter2;
  }
  // case 3: one has a circle, while the other not
  else
  {
    return false;
  }
}


完整代码如下:

// copyright @ L.J.SHOU Feb.27, 2014
// test whether two lists are intersected
#include <iostream>
#include <cassert>
using namespace std;

struct ListNode{
  int val;
  ListNode *next;
  ListNode(int x)
    :val(x), next(NULL){}
};

ListNode* HasCircle(ListNode*);
bool IsIntersectedCircle(ListNode*, ListNode*);

// version 1
// test whether two lists are intersected
// assume each list has no circle
bool IsIntersectedNoCircle(ListNode *lhs, ListNode *rhs)
{
  if(lhs == NULL || rhs == NULL)
    return false;

  ListNode *tail1(lhs);
  for(; tail1->next; tail1 = tail1->next);

  ListNode *tail2(lhs);
  for(; tail2->next; tail2 = tail2->next);

  return tail1 == tail2;
}

// version 2
// assume lists may have a circle inside 
bool IsIntersectedCircle(ListNode *lhs, ListNode *rhs)
{
  ListNode *enter1(NULL), *enter2(NULL);

  enter1 = HasCircle(lhs);
  enter2 = HasCircle(rhs);

  // case 1: both lists have no circles
  if(enter1 == NULL && enter2 == NULL)
  {
    return IsIntersectedNoCircle(lhs, rhs);
  }
  // case 2: each have a circle
  else if(enter1 && enter2)
  { 
    ListNode *node(enter1->next); 

	while(node != enter1 && node != enter2){
	  node = node->next;
	}
	return node == enter2;
  }
  // case 3: one has a circle, while the other not
  else
  {
    return false;
  }
}


// test whether list has a circle
// if true, return the enter node
// if not,  return NULL
ListNode* HasCircle(ListNode *list)
{
  if(list == NULL || list->next == NULL) 
    return NULL;

  // fast/slow pointer method
  // if circled, slow pointer will catch up with fast one
  ListNode *fast(list), *slow(list);

  while(fast)
  {
    fast = fast->next;
	if(fast == NULL) return NULL;
	fast = fast->next;
	slow = slow->next;

	if(fast == slow)
	  break;
  }
  assert(fast == NULL || slow == fast); 

  if(fast == NULL) 
    return NULL;

  // list definitely has a circle
  // find the enter node
  // fast and enter will meet at the enter node
  ListNode *enter(list);

  while(enter != fast)
  {
    enter = enter->next;
	fast = fast->next;
  }

  return enter;
}

// destroy list
ListNode* Destroy(ListNode *list)
{
  ListNode *next(NULL);

  while(list)
  {
    next = list->next;
	delete list;
	list = next;
  }

  return NULL;
}

int main(void)
{
  ListNode *list(NULL);

  // testing case 1: both have no circles
  list = new ListNode(1);
  list->next = new ListNode(2);
  list->next->next = new ListNode(3);

  ListNode *list2 = list->next;
  cout << IsIntersectedCircle(list, list2) << endl;

  // testing case 2: both have circles
  list2 = new ListNode(1);
  list2->next = new ListNode(2);
  list2->next->next = list->next;

  list->next->next->next = list->next;
  cout << IsIntersectedCircle(list, list2) << endl;

  list->next->next->next = NULL;
  list2->next->next = NULL;

  // testing case 3: only one has a circle
  list->next->next->next = list->next;
  cout << IsIntersectedCircle(list, list2) << endl;
  list->next->next->next = NULL;


  list = Destroy(list);
  list2 = Destroy(list2);

  return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值