题目
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例 :
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
想法一:哈希表
算法实现
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
dic = {}
cur = head
i = 0
while cur:
dic.update({i: cur})
cur = cur.next
i += 1
if i == n:
return head.next
elif n == 1:
dic[i - n - 1].next = None
else:
dic[i - n - 1].next = dic[i - n + 1]
return head
执行结果
执行结果 : 通过
执行用时 : 36 ms, 在所有 Python3 提交中击败了70.62%的用户
内存消耗 : 13.5 MB, 在所有 Python3 提交中击败了11.85%的用户
复杂度分析
-
时间复杂度:O(n),
我们一个链表所有节点。 -
空间复杂度:O(n)
需要额外的n个节点来储存链表每一个节点。扫描二维码关注公众号,回复: 10032272 查看本文章
两次遍历
算法实现
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
if not head or n <= 0:
return head
# 增加一个特殊节点,方便边界处理
p = ListNode(-1)
p.next, a, b, k = head, p, p, 0
# 第一次遍历,计算链表总长度
while a.next:
a, k = a.next, k + 1
# 如果链表总长度小于n,那就直接返回
if k < n:
return head
# 计算第二次遍历多少个节点
num = k - n
# 第二次遍历,找到要删除节点的前一个节点
while num > 0:
b, num = b.next, num - 1
# 删除节点,并返回
b.next = b.next.next
return p.next
执行结果
复杂度分析
-
时间复杂度:O(n),
该算法对列表进行了两次遍历。 -
空间复杂度:O(1)
一次遍历
算法实现
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
# 增加一个特殊节点方便边界判断
p = ListNode(-1)
p.next, a, b = head, p, p
# 第一个循环,b指针先往前走n步
while n > 0 and b:
b, n = b.next, n - 1
# 假设整个链表长5,n是10,那么第一次遍历完后b就等用于空了
# 于是后面的判断就不用做了,直接返回
if not b:
return head
# 第二次,b指针走到链表最后,a指针也跟着走
# 当遍历结束时,a指针就指向要删除的节点的前一个位置
while b.next:
a, b = a.next, b.next
# 删除节点并返回
a.next = a.next.next
return p.next
执行结果
复杂度分析
-
时间复杂度:O(n),
该算法对列表进行了一次遍历。 -
空间复杂度:O(1)
小结
先按照自己的想法设计,说道一次遍历想到的首先是哈希表,储存节点,然后查找,速度还算可以。
之后看了两次遍历,即先找到链表的长度,再重新遍历去删除。
一次遍历的另一种方式双指针很精妙,学到了=。=