Given a non-empty, singly linked list with head node `head`, return a middle node of linked list.
If there are two middle nodes, return the second middle node.
Example 1:
Input: [1,2,3,4,5]
Output: Node 3 from this list (Serialization: [3,4,5])
The returned node has value 3. (The judge's serialization of this node is [3,4,5]).
Note that we returned a ListNode object ans, such that:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, and ans.next.next.next = NULL.
Example 2:
Input: [1,2,3,4,5,6]
Output: Node 4 from this list (Serialization: [4,5,6])
Since the list has two middle nodes with values 3 and 4, we return the second one.
Note:
- The number of nodes in the given list will be between
1
and100
.
這道題給了一個鏈表,讓我們找其中間結點。由於鏈表不像數組,不能通過坐標位置來直接訪問元素,而是只能從頭結點開始,使用 next 指針來訪問之后的結點,為了知道當前結點的位置,還得使用計數器來記錄。由於在不知道鏈表的總長度之前,是無法知道中間結點的位置的,那么可以首先遍歷一遍,統計出鏈表的長度,此時長度有了,除以2就是中間結點的位置了,再從頭遍歷一遍,就可以找出中間結點的位置了,參見代碼如下:
解法一:
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *cur = head;
int cnt = 0;
while (cur) {
++cnt;
cur = cur->next;
}
cnt /= 2;
while (cnt > 0) {
--cnt;
head = head->next;
}
return head;
}
};
由於鏈表無法通過坐標位置來訪問元素,但我們可以將所有的結點按順序存入到一個數組中,那么之后就可以直接根據坐標位置來訪問結點了,參見代碼如下:
解法二:
class Solution {
public:
ListNode* middleNode(ListNode* head) {
vector<ListNode*> vec(100);
int cur = 0;
while (head) {
vec[cur++] = head;
head = head->next;
}
return vec[cur / 2];
}
};
上面兩種方法一個多用了時間,一個多用了空間,其實都不是最優的解法,最好的方法其實是使用快慢指針來做。在之前那道 [Linked List Cycle](https://www.cnblogs.com/grandyang/p/4137187.html) 鏈表中找環的題,我們介紹過快慢指針,就是兩個指針,慢指針一次走一步,快指針一次走兩步,那么這里當快指針走到末尾的時候,慢指針剛好走到中間,這樣就在一次遍歷中,且不需要額外空間的情況下解決了問題,參見代碼如下:
解法三:
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *slow = head, *fast = head;
while (head && head->next) {
slow = slow->next;
head = head->next->next;
}
return slow;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/876
類似題目:
參考資料:
https://leetcode.com/problems/middle-of-the-linked-list/
[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)