本人一直在努力地积累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.链表需特别注意边界情况