每天一道leetcode142-寻找链表中环的入口

  • 2019 年 10 月 4 日
  • 筆記

题目

每天一道leetcode142-寻找链表中环的入口 分类:链表 中文链接: https://leetcode-cn.com/problems/linked-list-cycle-ii/ 英文链接 https://leetcode.com/problems/linked-list-cycle-ii/

题目详述

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 说明:不允许修改给定的链表。 进阶: 你是否可以不用额外空间解决此题?

题目详解

使用额外空间的思路

  • 就是使用一个hashmap,去遍历一遍链表,每遍历一个链表,如果不存在这个节点,那么就插入hashmap,如果存在,说明这个节点已经插入了,那么这个节点就是重复的节点,为啥重复了,就是环的入口节点了。

代码

/**   * Definition for singly-linked list.   * class ListNode {   *     int val;   *     ListNode next;   *     ListNode(int x) {   *         val = x;   *         next = null;   *     }   * }   */  public class Solution {      public ListNode detectCycle(ListNode head) {          HashMap<ListNode,Integer> map = new HashMap<>();          if(head == null || head.next == null)              return null;          while(head != null)          {              if(map.containsKey(head) == false)              {                  map.put(head,1);                  head = head.next;              }else{                  return head;              }          }          return null;      }  }  

代码讲解

  • 15-22行,hashmap判断这个节点如果不存在,那么插入到hashmap里面;
  • 23-24行,hashmap中存在这个节点,那么就返回这个节点,也就是入口节点

不使用额外空间的思路

  • 使用快慢指针,快指针每次走两步,慢指针每次走一步,如果快慢指针相遇说明有环;
  • 有环以后,需要寻找环入口节点,已经找到了一个环的中的节点,利用这个节点,去往下遍历,由于是环,所以这个节点肯定会和自身相遇,相遇以后,记录相遇过程中走的步数,就是环的长度
  • 知道环的长度以后,然后再利用快慢指针的思想,快指针先走环长度,然后快慢指针再一起走,这样因为快指针先走了环的长度,当两者相遇肯定是环的入口节点相遇(为啥呢,因为快慢指针肯定会进入环里面,而由于快指针先走了环的长度,所以也就是一个周期,所以只要进入环,那么这两个指针必然相遇

代码

/**   * Definition for singly-linked list.   * class ListNode {   *     int val;   *     ListNode next;   *     ListNode(int x) {   *         val = x;   *         next = null;   *     }   * }   */  public class Solution {      boolean flag = true;      public ListNode detectCycle(ListNode head)      {          ListNode pHead = head;          if(pHead == null || pHead.next == null)              return null;          ListNode pNode = judgeHasChain(pHead);          if(pNode != null)          {              int lengthChain = 1;              ListNode pNodeCopy = pNode.next;              while(pNodeCopy != pNode)              {                  lengthChain++;                  pNodeCopy = pNodeCopy.next;              }              ListNode fast = pHead;              ListNode slow = pHead;              int temp = 0;              while(temp < lengthChain)              {                  fast = fast.next;                  temp++;              }              while(fast != slow)              {                  fast = fast.next;                  slow = slow.next;              }              return fast;          }          return null;      }      private ListNode judgeHasChain(ListNode pHead)      {          ListNode fast = pHead.next;          ListNode slow = pHead;          while(fast != slow)          {              if(fast != null && fast.next != null)              {                  fast = fast.next;              }else{                  flag = false;                  break;              }              if(slow != null && slow.next != null)              {                  slow = slow.next;              }else{                  flag = false;                  break;              }              if(fast == slow)              {                  return fast;              }else{                  fast = fast.next;              }          }          if(flag)              return fast;          return null;      }  }  

代码讲解

  • 46-76 就是判断链表中是否有环,之前有详细讲过 之前的文章链表:每天一道leetcode141-环形链表
  • 19行中,如果链表有环,那么返回的这个节点必然在环中
  • 22-28行,利用19行的节点,遍历计算环的长度
  • 32-36行,快指针先走环长度
  • 37-41行 快慢指针一起走,相遇就是环的入口节点