在数据结构的面试中,经常会出现这样的问题:如何快速找到未知长度单链表的中间节点?通常,面试官会期待你提供两种解法:一种是最基本的普通方法,另一种是更高效的 advanced 方法。本文将详细介绍这两种方法。
普通方法
思路
普通方法首先需要遍历整个链表以确定其长度 L。然后,再次从头节点出发,循环 L/2 次找到中间节点。
算法步骤
- 初始化一个变量 length 用于记录链表长度,将头节点 head 赋值给 length。
- 创建一个临时节点 temp,用于遍历链表,将头节点赋值给 temp。
- 遍历链表,每遍历一次,length 减一,直到 length 等于 0。
- 将 temp 重新赋值为头节点 head,循环 length/2 次,每次移动 temp 一步。
- 当循环结束时,temp 所指向的节点即为链表的中间节点。
时间复杂度
普通方法的时间复杂度为 O(L + L/2) = O(3L/2),其中 L 为链表的长度。
代码实现
struct ListNode {
int val;
struct ListNode* next;
};
struct ListNode* findMiddleNode(struct ListNode* head) {
int length = 0;
struct ListNode* temp = head;
while (temp != NULL) {
length++;
temp = temp->next;
}
temp = head;
for (int i = 0; i < length / 2; i++) {
temp = temp->next;
}
return temp;
}
高级方法
思路
高级方法使用快慢指针。快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针所指的节点就是链表的中间节点。
算法步骤
- 初始化两个指针,快指针 fast 和慢指针 slow,都指向头节点 head。
- 让快指针先移动,每次移动两步;慢指针移动一步。
- 当快指针到达链表的末尾时,慢指针所指向的节点就是链表的中间节点。
时间复杂度
高级方法的时间复杂度为 O(L),其中 L 为链表的长度。
代码实现
struct ListNode {
int val;
struct ListNode* next;
};
struct ListNode* findMiddleNode(struct ListNode* head) {
struct ListNode *slow = head, *fast = head;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
总结
本文介绍了在未知长度的单链表中快速找到中间节点的两种方法:普通方法和高级方法。普通方法虽然简单易懂,但其时间复杂度较高。相比之下,高级方法利用快慢指针,将时间复杂度降低到了 O(L),更为高效。在实际面试中,掌握这两种方法将对您解决链表问题大有裨益。