《剑指offer》23--链表中环的入口结点[C++]

 1 链表中环的入口结点

链表中环的入口结点_牛客题霸_牛客网【牛客题霸】收集各企业高频校招笔面试题目,配有官方题解,在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的技术能力https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=13&tqId=11208&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-rankinghttps://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=13&tqId=11208&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking题目描述

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

数据范围: n\le10000n≤10000,1<=结点值<=100001<=结点值<=10000

要求:空间复杂度 O(1),时间复杂度 O(n)

解题思路

【C++解法】

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

1、暴力解法

时间复杂度:o(n);空间复杂度:O(n)。不符合要求。

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if (pHead == NULL || pHead->next == NULL) {return NULL;}
        unordered_set<ListNode*> v;
        while(pHead != NULL) {
            if(v.count(pHead) > 0) {return pHead;}
            v.insert(pHead);
            pHead = pHead->next;
        }
        return NULL;
    }
};

2、快慢指针

时间复杂度:o(n);空间复杂度:O(1)。

两个结论:

1、设置快慢指针,假如有环,他们最后一定相遇。

2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。

证明1:设置快慢指针fast和slow,fast每次走两步,slow每次走一步。假如有环,两者一定会相遇(因为slow一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。

证明2:

设:

链表头到环入口长度为--a

环入口到相遇点长度为--b

相遇点到环入口长度为--c

则:相遇时

快指针路程=a+(b+c)m+b

慢指针路程=a+(b+c)n+b

其中b+c为环的长度,m为绕环的圈数(m>=1, n>0, m>n)。

快指针走的路程是慢指针的两倍,所以:

(a+(b+c)n+b)*2=a+(b+c)m+b

化简可得:

a=(m-n)(b+c)+c 这个式子的意思是: 链表头到环入口的距离=相遇点到环入口的距离+(m-n)圈环长度。其中m-n>0圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if (!pHead || !pHead->next) {return nullptr;}
        ListNode* fast = pHead;
        ListNode* slow = pHead;
        while (fast->next && fast->next->next) {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) {
                slow = pHead;
                while (slow != fast) {
                    slow = slow->next;
                    fast = fast->next;
                }
                return slow;
            }
        }
        return nullptr;
    }

3、如果允许修改链表

时间复杂度:o(n);空间复杂度:O(1)。

修改value做flag

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if (!pHead || !pHead->next) {return nullptr;}
        while (pHead != nullptr){
            if(pHead->val < 0) {
                pHead->val = - pHead->val;
                return pHead;
            }
            pHead->val = - pHead->val;
            pHead = pHead->next;
        }
        return nullptr;
    }
};

【Java解法】

1、暴力解法

import java.util.Set;
import java.util.HashSet;
public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead) {
        if (pHead == null) {return pHead;}
        Set<ListNode> vis = new HashSet<>();
        while (pHead != null) {
            if(vis.contains(pHead)) {return pHead;}
            else {vis.add(pHead);}
            pHead = pHead.next;
        }
        return null;
    }
}

2、快慢指针

public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead) {
        if(pHead == null || pHead.next == null) {return null;}
        ListNode fast = pHead;
        ListNode slow = pHead;
        while(fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow) {
                slow = pHead;
                while(slow != fast) {
                    slow = slow.next;
                    fast = fast.next;
                }
                
                return slow;
            }
        }
        return null;
    }
}

【同款LeetCode问题】

LeetCode-142. Linked List Cycle II [C++][Java]_贫道绝缘子的博客-CSDN博客Given theheadof a linked list, returnthe node where the cycle begins. If there is no cycle, returnnull.https://blog.csdn.net/qq_15711195/article/details/122519693

2 相关问题

【判断是否有环】

LeetCode-141. Linked List Cycle [C++][Java]_贫道绝缘子的博客-CSDN博客Givenhead, the head of a linked list, determine if the linked list has a cycle in it.https://blog.csdn.net/qq_15711195/article/details/122519333

【1-n间n+1个数字中的重复数字】

找出在[1, n]之间的n+1个数字中的重复数字,要求不能修改数组,也不能使用额外的空间。

LeetCode-287. Find the Duplicate Number [C++][Java]_贫道绝缘子的博客-CSDN博客Given an array of integersnumscontainingn + 1integers where each integer is in the range[1, n]inclusive. There is onlyone repeated numberinnums, returnthisrepeatednumber.https://blog.csdn.net/qq_15711195/article/details/122523324

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贫道绝缘子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值