LeetCode 19.删除链表的倒数第N个节点
题目:
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
思路:
最初的想法是,递归,但是对链表的特性跟递归的使用还是不熟悉,一时间没有想到对应的实现。
这里推荐一个递归的基础思路学习:https://www.cnblogs.com/kubidemanong/p/10538799.html
方法一:
取出每层节点的val值添加到新的列表中,重新创建符合条件的链表结构,这个是没有思考的思路= = 、。
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
temp = []
while(1):
if head.next:
temp.append(head.val)
head = head.next
else:
temp.append(head.val)
break
if len(temp)==1:
return None
temp.pop(len(temp)-n)
res = ListNode(temp[0])
res_temp = res
for i in xrange(1,len(temp)):
res_temp.next = ListNode(temp[i])
res_temp = res_temp.next
return res
执行用时:12 ms, 在所有 Python 提交中击败了99.71%的用户
内存消耗:12.8 MB, 在所有 Python 提交中击败了9.09%的用户
方法二:
递归思路,递归的三要素,明确函数功能,找到终止条件,找到等价关系。
这里前后各print了一下head和head.next, 你就会发现递归真有意思,这个题目倒序删除的要求简直就是为递归量身定做。
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
global i
if head is None:
i=0
return None
print head,head.next
head.next = self.removeNthFromEnd(head.next,n)
i+=1
print '******'
print i,n,head,head.next
return head.next if i==n else head #i=n时,head=head.next.next删除指定n
'''
预期结果
[1,2,3,5]
ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 3, next: ListNode{val: 4, next: ListNode{val: 5, next: None}}}}} ListNode{val: 2, next: ListNode{val: 3, next: ListNode{val: 4, next: ListNode{val: 5, next: None}}}}
ListNode{val: 2, next: ListNode{val: 3, next: ListNode{val: 4, next: ListNode{val: 5, next: None}}}} ListNode{val: 3, next: ListNode{val: 4, next: ListNode{val: 5, next: None}}}
ListNode{val: 3, next: ListNode{val: 4, next: ListNode{val: 5, next: None}}} ListNode{val: 4, next: ListNode{val: 5, next: None}}
ListNode{val: 4, next: ListNode{val: 5, next: None}} ListNode{val: 5, next: None}
ListNode{val: 5, next: None} None
******
1 2 ListNode{val: 5, next: None} None
******
2 2 ListNode{val: 4, next: ListNode{val: 5, next: None}} ListNode{val: 5, next: None}
******
3 2 ListNode{val: 3, next: ListNode{val: 5, next: None}} ListNode{val: 5, next: None}
******
4 2 ListNode{val: 2, next: ListNode{val: 3, next: ListNode{val: 5, next: None}}} ListNode{val: 3, next: ListNode{val: 5, next: None}}
******
5 2 ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 3, next: ListNode{val: 5, next: None}}}} ListNode{val: 2, next: ListNode{val: 3, next: ListNode{val: 5, next: None}}}
'''
方法三:
一次遍历(来自题解王尼玛大大的思路分享).
当链表总长度是k时,如果要删除倒数第n个节点(假设n小于k),那么首先要找到第k-n个节点,k-n这个节点就是要删除的节点的前一个节点。
当找到k-n这个节点就好办了,直接将k-n的next指针指向下下一个节点即可。
我们需要两个指针a和b。
b指针先走n步,接着a和b指针同时往前走,当b指针走到链表末尾时,a指针就正好走到要删除的节点的前一个位置了,最后a节点的next指针指向下下一个节点,就可以完成删除操作了。
思路很清晰啊有木有,真棒... 顺便diss下自己😂
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
# 增加一个特殊节点方便边界判断
# 对于删除节点类的链表题目,我们都可以构造一个虚拟节点指向表头,
# 方便代码边界的处理,比如node.next.next,就不用担心空异常
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
方法四:
二次遍历( 来自王尼玛的题解,因为别人的思路和注解要比我清楚的多....感谢分享😂)
两次遍历的方式很好理解,先遍历一次链表,求出链表的总长度。
第二次遍历的时候,根据总长度k的值-n,就算出需要再遍历多少个节点,找到要删除的节点的前一个节点x。
然后将x节点的next指针指向下下一个节点就可以删除节点了。
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: 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