题目:给定一个头结点为 head
的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
示例1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
思路:
思路一:找规律
1 -> 3 -> 5 返回 3 所在的结点,要跳 1 步
1 -> 3 -> 5 -> 7 返回 5 所在的结点,要跳 2 步
总结规律可以得出:要跳的步数即循环的次数:元素个数 / 2 (自动向下取整)
代码:
//求链表中元素个数
public static int size(ListNode head){
ListNode cur = head;
int size = 0;
while (cur != null){
size++;
cur = cur.next;
}
return size;
}
public ListNode middleNode(ListNode head) {
ListNode cur = head;
int size = size(head);
for (int i = 0;i < size / 2; i++){
cur = cur.next;
}
return cur;
}
思路二:双指针遍历
双指针遍历思路是oj题中很常见的一种思路。这里使用快慢引用的方法,即
慢引用一次走1步,快引用一次走2步。
逻辑上,两个引用同时走,当快引用到达结尾指向 null 时,慢引用在中间位置。因此需要判断快引用是否指向 null 。
则就有三种情况:
慢 -> 快 -> 快
快 -> 慢 -> 快
快 -> 快 -> 慢
加上判断语句的话:
慢 ->判断 -> 快 -> 判断 -> 快
慢 -> 快 -> 判断 -> 快 -> 判断 (剩下两种情况类似)
情况不同,写出来的代码也不太一样
代码:
public ListNode middleNode(ListNode head) {
ListNode fast = head;
ListNode slow = head;
//根据情况二写代码:快 -> 判断 -> 慢 -> 快 -> 判断
while (true){
fast = fast.next;
if (fast == null){
return slow;
}
slow = slow.next;
fast = fast.next;
if (fast == null){
return slow;
}
}
}