本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目链接: leetcode.com/problems/mi…
1. 题目介绍(链表中点)
Given the head of a singly linked list, return the middle node of the linked list. 【Translate】: 给定单链表的头部,返回链表的中间节点。
If there are two middle nodes, return the second middle node. 【Translate】: 如果有两个中间节点,则返回第二个中间节点。
测试用例:
约束:
2. 题解
2.1 快慢指针
针对链表问题,快慢指针是一个很好的解决方案。通过快慢指针我们可以快速的判断出中点位置,进而进行相应的操作。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
// 当链表中只存在一个节点时,直接返回它本身
if (head == null || head.next == null) {
return head;
}
// 定义快慢指针
ListNode quick = head;
ListNode slow = head;
// 移动快慢指针,并做奇偶情况判断
while(quick.next != null){
slow = slow.next;
if(quick.next.next != null){ // 奇
quick = quick.next.next;
}else{ // 偶
quick = quick.next;
}
}
return slow;
}
}
2.2 精简版快慢指针
上面的代码是我自己写的,难免有些啰嗦。下面是Most Vote中排名最高的题解:
public ListNode middleNode(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
我们可以看出,虽然语句变得简洁了很多,但是性能其实并没有得到多少提升。
2.3 遍历确定中点
该方法没有使用快慢指针来确定中点,而是通过传统的遍历首先确定链表的长度,然后根据总长度确定中点位置。
public ListNode middleNode(ListNode head) {
ListNode curr = head;
int total = 0;
while(curr != null){
total++;
curr = curr.next;
}
//find the middle one
total = total/2 + 1;
ListNode cur = head;
for(int i = 1; i < total; ++i){
cur = cur.next;
}
return cur;
}