问题:
给定一个头结点为
head
的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
示例1:
输入:[1,2,3,4,5]
输出:第三个元素示例2:
输入:[1,2,3,4,5,6]
输出:第4个元素
咱就是说,看到题目简单的不行,暴力咔咔就解出来了,不就是第一次遍历链表,得出链表长度;第二次遍历链表的一半么。一顿操作猛如虎,结果出来二百五。是通过验证了没错,但这效率也太差了,太不程序员了吧!
以下是 朴素解法:咦~(地铁老人)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def middleNode(self, head: ListNode) -> ListNode:
length = 1
cur = head
li = []
while 1:
li.append(cur)
if not cur.next:
break
cur = cur.next
length += 1
return li[int(length/2)]
后来经过学习其他人的思路,可以通过 快慢指针 来做这题。
快慢指针:比较经典的做法是:
使用两个指针变量,刚开始都位于链表的第 1 个结点,一个永远一次只走 1 步,一个永远一次只走 2 步,一个在前,一个在后,同时走。这样当快指针走完的时候,慢指针就来到了链表的中间位置。
简单点,咱可以换成小学数学题目来看,假设链表长度为S,快指针每次走2步,速度为2v;慢指针每次走1步,速度为v;那么可以得到下面公式。
S = 2v * t (快指针)
S/2 = v * t (慢指针)
也就是说,当快慢指针起点相同时,慢指针永远是快指针的一半。
最后,给出快慢指针解法代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def middleNode(self, head: ListNode) -> ListNode:
slow = head
fast = head
while 1:
if fast and fast.next:
fast = fast.next.next
slow = slow.next
else:
break
return slow
大家可以看下效率比较:
最后感慨一下:算法yyds