剑指offer - 55链表中环的入口

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

有下面三种方法:

1. 遍历链表,使用map保存每个节点是否出现过,第一个出现两次的的节点就是环的入口

2. 断链法,遍历每一个节点,使其next为NULL,则最后一个next为空的节点就是入口

3. 快慢指针法,慢指针每次走一步,快指针每次都两步,则两个必然在环内相遇,

    相遇后快指针从head开始,每次走一步,慢指针在环内继续每次走一步,则相遇点为入口

    证明如下,设链表开始到入口长度为x, 环长度为c, 环入口到第一次相遇点长度为a

    则慢指针走的路程为  Sslow = x + c*m + a, 快指针走的路程为 Sfast = x + c*n + a,并且 2 * Sslow = Sfast

    所以可以导出 x = (n - 2 * m )*c - a = (n - 2 *m -1 )*c + c - a

    c - a 是从相遇点,到入口的长度

    也就是说,如果再有两个新指针,一个从头开始走,另一个从第一次的相遇点继续走, 则必然在入口再次相遇

代码如下:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    //方法一:快慢指针
    ListNode* entrynode_2pointer(ListNode* head){
        if(NULL == head || NULL == head->next){
            return NULL;
        }
        ListNode* slow = head;
        ListNode* fast = head;
        while(NULL != fast && NULL != fast->next){
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast){
                fast = head;
                while(slow != fast){
                    slow = slow->next;
                    fast = fast->next;
                }
                return slow;
            }
        }
        return NULL;
    }
    //方法二:断链法
    ListNode* entrynode_breaklink(ListNode* head){
        if(NULL == head || NULL == head->next){
            return NULL;
        }
        ListNode* node = head;
        while(node->next){
            ListNode* temp = node->next;
            node->next = NULL;
            node = temp;
        }
        return node;
    }
    //方法三:使用map保存节点是否出现过,第一个出现两次的节点就是入口
    ListNode* entrynode_map(ListNode* head){
        if(NULL == head || NULL == head->next){
            return NULL;
        }
        map<ListNode*, int> nodemap;
        ListNode* node = head;
        while(node){
            if(nodemap[node] == 1){
                return node;
            }
            else{
                nodemap[node] = 1;
                node = node->next;
            }
        }
        return NULL;
    }
    
    ListNode* EntryNodeOfLoop(ListNode* pHead){
        //turn entrynode_2pointer(pHead);
        //return entrynode_breaklink(pHead);
        return entrynode_map(pHead);
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值