本人一直在努力地积累Leetcode上用Python实现的题,并且会尽力讲清每道题的原理,绝不像其他某些博客简略地带过。
如果觉得讲的清楚,欢迎关注。
如果觉得讲的清楚,欢迎关注。
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
思路:首先要明确我们要删除的是倒数第n个节点,而不是正数的,但是要删除节点我们只能从头部进入,这样的话如果我们只知道删除倒数第几个是做不了的,我们还需要知道这个链表一共有多少个,然后通过数学运算知道我们是删正数第几个。
所以以下是我写的, 效率还不错, beat 88。
class Solution:
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
t = head
count = 0
#第一次遍历用count求有多少个节点
while t != None:
t = t.next
count += 1
#求我们要正数第几个
order = count - n
index = 1
t = head
while index < order:
t = t.next
index+=1
#考虑说一共有5个节点,然后让我们求倒数第5个这种情况
#我们直接把头节点的下一项当作头节点返回
if order == 0:
return head.next
#其他情况,完成删除
l = t.next
t.next = l.next
return head
但同时这道题的进阶是让我们实现以一趟扫描完成。这听起来有点荒谬,我们一趟扫描才刚知道有几个节点呀,怎么做删除?
但其实我们假设我们有n个节点,我们的目标是删除倒数第k个节点,则我们需要走n-k步。那么怎么让一个指针在一趟扫描走n-k步呢?那就是设置2个指针。我们设置一个快指针,让它先走k步,此时它领先另一个慢指针k步。接着同时启动快慢指针,一起向尾部运动,当快指针走到底时,它走了n步(从头到底有n个节点), 第二阶段速度相同,第一阶段快k步,所以慢指针走了n-k步!刚好与我们预期相符!!
知道了这个算法后,我尝试自己实现了一下:
class Solution:
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
#有一个dummy节点在head节点前面,它的目的是让我们走n步能到原链表正数第n个节点
Dummy = ListNode(0)
Dummy.next = head
fast = slow = Dummy
#快节点先走n步
for i in range(n):
fast = fast.next
#快慢节点同时启动
while fast.next is not None:
fast = fast.next
slow = slow.next
#删除
slow.next = slow.next.next
return Dummy.next
但是只beat 了3.32。。。leetcode 的记时有点迷啊
反思易错:
1.增加dummy节点方便我们移动,前进n步走到第n个节点
2.one pass 可通过快慢指针实现
3.链表需特别注意边界情况