每天一道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行 快慢指針一起走,相遇就是環的入口節點