zoukankan      html  css  js  c++  java
  • Leetcode#141,#142_环形链表(剑指Offer#23)

    Leetcode#141,#142_环形链表(剑指Offer#23)

    Contents

    • 剑指Offer#23,Leetcode上面没有,是在牛客上做的,链接:链表中环的入口结点
    • leetcode#141,#142题和此题类似,所以连同这两题一起做。

    Leetcode #141 环形链表

    题目

    给定一个链表,判断链表中是否有环。
    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

    思路分析

    双指针法

    设置一快一慢两个指针,慢指针每次走1步,快指针每次走2步。两个指针同时开始遍历链表。
    指针进入环形部分后,两个指针的运动过程类似于我们学过的追及问题。两个指针都在绕圈,一个快,一个慢,那么快指针必然会追上慢指针。
    也就是,当快指针和慢指针相遇时,说明相遇的位置就是环里的一个节点,也就证明链表有环。
    否则,快指针必定先遇到null,这时直接证明链表没有环(有环就不可能遇到null,而是可以一直绕着环移动)。
    特殊输入

    • 输入空链表,直接返回false。
    • 只有一个节点(有环或五环)的情况,可以代入代码验证。

    问题
    快指针每次走2步,慢指针每次走1步,那么会不会出现刚好快指针超过慢指针1步,二者刚好错过,不能相遇情况呢?
    解答
    不会出现这种情况,因为如果快指针刚好超过慢指针1步,那说明上一轮迭代时是相遇的。其他情况也类似:

    • 如果快指针落后慢指针1步,那么下一轮迭代就会相遇。
    • 如果快指针落后慢指针2步,那么下两轮迭代就会相遇。
      ...

    总结规律就是,快指针和慢指针的运动是相对的,每次快指针相对慢指针靠近1步,所以不会出现因为快指针走2步而错过相遇点的情况。

    解答

    public class Solution {
        public boolean hasCycle(ListNode head) {
            if(head == null) return false;
            ListNode fast = head.next;
            ListNode slow = head;
            while(fast != slow){//fast和slow指针相遇时,循环结束,证明有环
                //因为fast指针更新的时候,需要访问fast.next.next,所以fast.next不可以是null
                if(fast == null || fast.next == null) return false;
                slow = slow.next;//slow前进1步
                fast = fast.next.next;//fast前进2步
            }
            return true;     
        }
    }

    Leetcode #142 环形链表II

    题目

    给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
    说明:不允许修改给定的链表。

    思路分析

    这题与剑指Offer#24相同。
    整个问题可以分解为三个子问题:

    1. 寻找环里的其中一个节点(即上述的Leetcode#141题),如果找不到,说明没有环,返回false。
      • 快慢指针法,相遇节点记为meetNode
    2. 计算环的周长
      • 快慢指针在meetNode处相遇,这时慢指针不动,快指针向后遍历,直到遇到慢指针,这个过程快指针走过的步数就是环的周长,记作n
    3. 寻找环的入口节点
      • 重置快慢指针,都指向链表头节点
      • 快指针先走n步,然后快慢指针一起走,每次走一步
      • 由于快指针多走了n,也就是比慢指针多走了环的一圈,所以当慢指针到达环入口节点时,快指针也刚好走完一圈,回到入口节点。快慢指针相遇处就是环入口节点。

    解答

    public class Solution {
        //两个指针是类内公用的
        ListNode fast;
        ListNode slow;
        public ListNode detectCycle(ListNode head) {
            ListNode meetNode = findMeetNode(head);
            if(meetNode == null) return null;//无环
            int cycleNum = countCycleNum(meetNode);
            fast = head;
            slow = head;
            for(int i = 1; i <= cycleNum;i++){//fast先走环周长那么多步
                fast = fast.next;
            }
            while(fast != slow){//同时移动,直到相遇
                fast = fast.next;
                slow = slow.next;
            }
            return fast;       
        }
        //寻找相遇节点,同141题
        public ListNode findMeetNode(ListNode head){
            if(head == null) return null;//没有环,返回null
            slow = head;
            fast = head.next;
            while(fast != slow){
                if(fast == null || fast.next == null) return null;//没有环,返回null
                slow = slow.next;
                fast = fast.next.next;
            }
            return fast;   
        }
    
        public int countCycleNum(ListNode meetNode){
            fast = fast.next;//fast先走一步,否则无法进入循环
            int cycleNum = 1;//由于已经走了一步,所以直接初始化为1
            while(fast != slow){
               fast = fast.next;
               cycleNum++;
            }
            return cycleNum;
        }
    }

    剑指Offer#23 链表中环的入口节点

    链接:链表中环的入口结点
    本题和leetcode 142一样,按照142题写法,修改下函数输入参数名,即可通过。

  • 相关阅读:
    函数集
    2019.1.7
    第九次团队作业-测试报告与用户使用手册
    α版本升升备忘录下载链接
    系统设计和任务分配(个人)
    团队作业说明
    备忘录-团队选题报告
    需求分析与原型设计---升升备忘录
    项目——四则运算器
    Hello Django
  • 原文地址:https://www.cnblogs.com/Howfars/p/13214117.html
Copyright © 2011-2022 走看看