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
posted @ 2020-06-23 11:30  萧蔷ink  阅读(161)  评论(0编辑  收藏  举报