一道面试题,考了我两次,两次都不会T_T

这道题记忆犹新啊,校招期间,被两家公司都问了,深信服和百度!!!坑爹。。。

然后csdn上发现了http://blog.csdn.net/fty8788/article/details/6531280    本文大部分来自这里

题目很简单:如何检查一个单链表上是否有环?

首先,既然是单链表,如果有环,就肯定是在链表末尾位置。


1. 首先想到的办法当然是把地址保存起来,然后遍历,重复出现的时候就表示此链有环,保存可以用哈希表,时间复杂度是O(n)

2. 第二个方法比较巧妙,试用反转指针,每过一个节点都把该节点的指针反转。

 Boolean reverse(Node *head) {
   Node *curr = head;
   Node *next = head->next;
   curr->next = NULL;

   while(next!=NULL) {
    if(next == head) { /* go back to the head of the list, so there is a loop */
      next->next = curr;
      return TRUE;
    }
    Node *temp = curr;
    curr = next;
    next = next->next;
    curr->next = temp;
   }

   /* at the end of list, so there is no loop, let's reverse the list back */
   next = curr->next;
   curr ->next = NULL;
   while(next!=NULL) {
    Node *temp = curr;
    curr = next;
    next = next->next;
    curr->next = temp;
   }
   return FALSE;
  }

好像代码不是那么好理解,不过自己在纸上跑一遍就会明白了。核心在:如果存在环最终链表遍历后会回到起点,如果不存在则不会,最后重新将反转后的链表反转回去

优点就是空间复杂度是O(1),只用了三个指针,时间复杂度为O(n),但是有个缺点:在多线程情况下会出现改变表的状态。


3. 第三个办法就是一般情况下的所谓的答案了,快慢指针,记得深信服的面试官曾想过把我往这方面指引,只怪我当时大脑一时没反应过来啊

int   is_link_list_cicled(Node*   head)    
{    
    Node   *p   =   head,   *q   =   head;    
    while(p   &&   q)    
    {                        
         p   =   p-> next;    
         q   =   q-> next;    
         if(!q)    
             return   0;    
         q   =   q-> next;    
         if(p   ==   q)    
             return   1;    
    } 
    return 0; 
}  

至于如何证明这样做的正确性,数学学的不错的应该很容易吧。。。

接下来,扩展一下,如何找到那个环的入口点:这个算法理解起来比较难,慢慢啃吧。。。

slist* FindLoopPort(slist *head)  
{  
    slist *slow = head, *fast = head;  
  
    while ( fast && fast->next )   
    {  
        slow = slow->next;  
        fast = fast->next->next;  
        if ( slow == fast ) break;  
    }  
  
    if (fast == NULL || fast->next == NULL)  
        return NULL;  
  
    slow = head;  
    while (slow != fast)  
    {  
         slow = slow->next;  
         fast = fast->next;  
    }  
  
    return slow;  
}  








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值