zoukankan      html  css  js  c++  java
  • 面试题 02.08. 环路检测 快慢指针

    给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。
    有环链表的定义:在链表中某个节点的next元素指向在它前面出现过的节点,则表明该链表存在环路。

    示例 1: 

    输入:head = [3,2,0,-4], pos = 1
    输出:tail connects to node index 1
    解释:链表中有一个环,其尾部连接到第二个节点。

    示例 2:

    输入:head = [1,2], pos = 0
    输出:tail connects to node index 0
    解释:链表中有一个环,其尾部连接到第一个节点。

    示例 3:

    输入:head = [1], pos = -1
    输出:no cycle
    解释:链表中没有环。

    方法:快慢指针

    概念:快慢指针是指移动的步长,即每次向前移动速度的快慢。(例如,让快指针每次沿链表向前移动2,慢指针每次向前移动1)

    1. 判断存不存在环路:当快指针到达NULL的时候,说明不存在环路。遍历就可以。

    2. 找到环入口:

    假设从头结点开始,有a个结点在环外,环中有r个结点。快指针和慢指针都从头指针出发,快指针每次走 2 步,慢指针每次走 1 步,在经过一段时间以后,在环中相遇,距离环入口的距离是 X。

    此时,慢指针走过的路程为 a+X;

    如果 a 较大的话,快指针可能现在已经在环中走过几圈了,假设快指针从入环开始已经走过 k(k>=1) 个整圈,则快指针走过的路程为 a+X+k*r;

    快指针走过的路程是慢指针的 2 倍,所以 2*(a+X) = a+X+k*r,即 a = k*r - X = (k-1)*r + r - X;

    观察一下,r-X 正好是相遇结点到环入口的距离 ,也就是说,如果现在让慢指针从头结点出发,快指针从相遇结点出发,每次步长均为 1,它们会在环入口相遇。

    代码:

     1 /**
     2  * Definition for singly-linked list.
     3  * struct ListNode {
     4  *     int val;
     5  *     ListNode *next;
     6  *     ListNode(int x) : val(x), next(NULL) {}
     7  * };
     8  */
     9 class Solution {
    10 public:
    11     ListNode *detectCycle(ListNode *head) {
    12         ListNode* pro;//快指针
    13         ListNode* last;//慢指针
    14         pro = head;
    15         last = head;
    16         if(!head) return head;
    17         do{
    18             if(!pro->next) return pro->next;
    19             pro = pro->next;
    20             last = last->next;
    21             if(!pro->next) return pro->next;
    22             pro = pro->next;
    23         }while(pro != last);
    24 
    25         last = head;
    26         while(pro != last){
    27             pro = pro->next;
    28             last = last->next;
    29         }
    30 
    31         return last;
    32     }
    33 };

    快慢指针的其他应用:

    1. 在有序链表中寻找中位数。原理:快指针移动速度是慢指针移动速度的两倍。所以快指针到达链表尾时,慢指针到达中点。(需要判断链表节点奇偶数)如果快指针移动x步到达表尾则为奇数。若为倒数第二个节点则为偶数(可根据规则返回上中位或下中位或上下一半);

    2. 两个单向链表判断他们是否相交

    思路:首先用快慢指针判断是否有环

    1)如果都没有环,如果两个单链表有公共结点,则两个单链表从某个结点开始,他们的next指向同一结点。(由于是单链表结点,每一结点只有一个next,所以从第一个公共结点开始,他们所有结点都是重合的)。既若两个单链表的末尾结点相同则相交。寻找第一个相交结点的方法:

    a.在其中一个单链表上顺序遍历每个结点,每遍历一个结点,在另外一个链表上顺序遍历每个结点。

    b.首先两个链表各遍历一次求表长l1,l2,两链表差为l.然后现在长的链表上遍历L,然后同步遍历,第一个相同的结点就是公共结点。时间复杂度(O(m+n))

    2)如果一个存在环,另外一个不存在环则不可能相交。

    3)如果利用快慢指针发现两单链表都存在环,则判断一个链表上快慢指针相遇的那个结点是否在另一个链表上。如果在则相交,否在不相交。如果相交,两个链表的入口点可能不是环上同一结点,利用上边的方法分别找出各自的入口点,可以定义任意一个入口点为相交的第一个结点。

  • 相关阅读:
    Mysql的ONLY_FULL_GROUP_BY
    Redis报错“ OOM command not allowed when used memory > 'maxmemory' ”
    redis发布订阅客户端报错
    使用IDEA远程调试SpringBoot程序
    kafk学习笔记(一)
    Ubuntu中卸载node和npm并重装
    一些常用的类型转换
    一台电脑配置多个GigHub账号
    百度网盘文件直接下载方法(跳过每次需要启动百度网盘下载的方式)
    如何激活IDEA工具,亲测有效
  • 原文地址:https://www.cnblogs.com/mujin-chuyang/p/13924359.html
Copyright © 2011-2022 走看看