【LeetCode】使用栈一次性解决 19. Remove Nth Node From End of List 问题

19. Remove Nth Node From End of List

n/a

0 ListNode

0.1 原解决代码模板

n/a

0.2 根据 LeetCode 提供的 ListNode 实现自己动手实现一个用于 debug

可以在 Jupyter Notebook 中使用。

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
    
    def __repr__(self):
        curr_node = self
        s = ''
        while curr_node.next:
            s += "{}->".format(curr_node.val)
            curr_node = curr_node.next
        s+= "{}".format(curr_node.val)
        return s

使用示范:
n/a

1 Solution

1.0 分析

思路:
O(n) 的复杂度是必须的,因为这是单向链表,所以肯定是必须要遍历到最后一个才能往前数 n 个。

3 -> 8 -> 1 -> 2 -> 4 ->7 -> 5
输入为 2
3 -> 8 -> 1 -> 2 -> 4 ->7 -> 5
                        2    1
拆键与链接
3 -> 8 -> 1 -> 2 -> 4 -x 7 -> 5
                     \       /|\
                      `-------'

可以看见,关键就是确定要移除的 node, 同时要在内存中暂留这个 node,因为我们需要用到它的 node->next
另一个就是需要获得要移除的 node 的上一个 node,用来链接剩下的链表

为什么可以使用栈来实现?

因为

  1. 栈可以保有每一个 node 信息。
  2. 栈的弹出顺序我们从链表末尾开始往前数的顺序是一样的。
  3. 我们一直把栈一直弹出 n-1 个 node,这些都是不需要的,在弹出第 n 个的时候,进行 拆键与链接 动作就结束了。
1.1 简单栈功能实现代码
class Stack:
    def __init__(self, listnode=None):
        self._stack = list()

        if listnode:
            __curr_node = listnode
            while __curr_node:
                self._stack.append(__curr_node)
                __curr_node = __curr_node.next

    def push(self, node):
        self._stack.append(node)

    def pop(self):
        return self._stack.pop()

    def pick(self):
        return self._stack[-1]

    def __len__(self):
        return len(self._stack)

栈使用示范:
n/a

因为上面自己动手实现的 ListNode 含有 __repr__,所以这里使用 stack.pick() 能够显示有用的信息。

1.2 一些特殊情况先了解一下
1.2.1 正常的测试用例示范:

n/a

1.2.2 nlistnode 都是 1

n/a
显示上为 [] 和 LeetCode 的机制有关系。本题为了显示,LeetCode 后台将程序运行的结果进一步转换然后显示在网页上。

1.3 使用栈解决方案的最终提交代码
class Solution:
    class Stack:  # 将上面的栈实现拿来用
        def __init__(self, listnode=None):
            self._stack = list()

            if listnode:
                __curr_node = listnode
                while __curr_node:
                    self._stack.append(__curr_node)
                    __curr_node = __curr_node.next
                    
        def push(self, node):
            self._stack.append(node)
        
        def pop(self):
            return self._stack.pop()
            
        def pick(self):
            return self._stack[-1]

        def __len__(self):
            return len(self._stack)
            
    
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        stack = self.Stack(head)
        if n == len(stack):  # 上文提到的特殊情况
            if len(stack) == 1:
                return None
            return head.next
        
        cnt = 0
        while True:  # 这段代码可以简化地很短,但是为了方便符合思路,就不进一步调整了
            node = stack.pop()
            if (cnt + 1) != n:
                cnt += 1
            else:  # finish
                _ = stack.pick()
                _.next = node.next
                break
        return head

2 运行结果

n/a

3 其它特殊输入了解

3.1 空 ListNode 输入

n0
n/a

n 不为 0

n/a

3.2 n 超过 listnode 的长度

n/a

随手写的特殊情况 case。条件严格来说没有经过完整地思考,放在这里只是为了在代码中需要考虑特殊输入 提个醒。


    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        case_1 = "Line 22: AttributeError: 'NoneType' object has no attribute 'next'"
        case_2 = "Line 14: AttributeError: 'NoneType' object has no attribute 'next'"
        case_3 = "Line 20: AttributeError: 'NoneType' object has no attribute 'next'"

        stack = self.Stack(head)
        if n > len(stack):
            return case_2
        if head is None:
            return case_3
        if n == 0:
            return case_1

因为这一题比较特殊,没有上述说的这种“不合规范”的输入,所以这部分判断可以不用。

即用于本题的 (208 个)测试用例(输入)? 没有上面提到的几种特殊情况。
n/a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值