#876. Middle of the Linked List

題目描述

給你一個單向鏈結串列的起點head,回傳中間的節點。

如果中間有兩個節點,回傳第二個節點。

限制條件

  1. 節點的數量為[1, 100]。
  2. 1 <= 節點值 <= 100

解題思路

Intuition

最直覺的方式,就是先取得全部的節點數量,除以2之後就是中間節點的位置,然後再重新碰到連結串列的位置就可以了。

public class Solution {
    public ListNode MiddleNode(ListNode head) {
        int count=0;
		var countNode = head;
		while(countNode!=null){
			countNode = countNode.next;
			count++;
		}
		int mid = count/2;
		for(int i=0;i<mid;i++){
			head = head.next;
		}
		return head;
    }
}

複雜度分析:

  • 時間複雜度:總共會經過3/2n的節點,因此時間複雜度為O(n)。
  • 空間複雜度:空間複雜度為O(1)。

Improve Intuitive Solution

如果要降低查詢的時間的話,可以用空間換時間的方式,利用Hash Table把節點位置記下來,就可以直接回傳中間值了。

public class Solution {
    public ListNode MiddleNode(ListNode head) {
        var ht = new Hashtable();
        int count=0;
		var countNode = head;
		while(countNode!=null){
            ht.Add(count,countNode);
			countNode = countNode.next;
			count++;
		}
		int mid = count/2;		
		return (ListNode)ht[mid];
    }
}

複雜度分析:

  • 時間複雜度:雖然有Hash Table幫忙減少了重新到達中間節點那一半的時間,但是時間複雜度仍然算O(n)。
  • 空間複雜度:空間上由於會記錄到全部的節點,因此時間複雜度會是O(n)。

Two Pointers

最好的方式是使用雙指標(Two Pointers),建立快慢節點,快節點的前進速度是慢節點的兩倍,當快節點到達尾端的時候,慢節點就會剛好落在中間的位置。

舉例來說,假設節點數量是10,快慢節點同時從1出發,當慢節點走到2的時候,快節點會是3,依序下去會是(慢,快):(1,1)->(2,3)->(3,5)->(4,7)->(5,9)->(6,11),當快節點走到底時,慢節點正好是中間節點的第二個位置,也就是我們要的答案。

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

複雜度分析:

  • 時間複雜度:實際上只花了一半的時間,但是時間複雜度還是要算O(n),但比起前兩個解法所花的時間O((3/2)*n)、O(n)來說,還是快了一些。
  • 空間複雜度:而空間複雜度上就比使用Hash Table還要來的少,空間複雜度為O(1)。

學習重點

  • 雙指標
Last Updated:
Contributors: eisen