【问题标题】:Python delete a node in linked list, given just access to that nodePython删除链表中的节点,只要访问该节点
【发布时间】:2016-08-10 16:49:49
【问题描述】:

这是一个 LeetCode 问题,我知道它的解决方案,但想知道为什么我的代码不起作用。

编写一个函数来删除单链表中的一个节点(除了尾部),只允许访问该节点。

假设链表是 1 -> 2 -> 3 -> 4 并且给定第三个值为 3 的节点,调用函数后链表应该变为 1 -> 2 -> 4

乍一看,我的直觉是像数组一样删除:

将所有节点值向前移动,然后删除尾部,这是我的实现和测试用例:

class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None
        
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node4 = ListNode(4)
node5 = ListNode(5)

node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5


    
def deleteNode(node):
    """
    :type node: ListNode
    :rtype: void Do not return anything, modify node in-place instead.
    """
    while node.next:
        node.val = node.next.val
        node = node.next
    node = None
    
    
deleteNode(node4)

但删除后,它有两个5值节点,尾部仍然保留,谁能解释一下这里出了什么问题?

deleteNode(node4)

node1.val
Out[162]: 1

node1.next.val
Out[163]: 2

node1.next.next.val
Out[164]: 3

node1.next.next.next.val
Out[165]: 5

node1.next.next.next.next.val
Out[166]: 5

非常感谢任何帮助。

【问题讨论】:

    标签: python algorithm linked-list


    【解决方案1】:

    您快到了,但是将所有 val 值向上移动一个节点做太多工作。您也未能清除最后一个 next 引用,这就是您看到 5 打印两次的原因。我会先告诉你如何正确解决问题,然后解决去除尾巴的问题。

    您确实可以通过删除节点来解决这个难题,只需将value 设置为下一个值,并将next 指针设置为下一个之后的节点。这就是您需要做的全部,您无需触及以下任何节点。您将有效地删除下一个节点并让 this 节点保持下一个值:

          node
           |
           v
          ---------        ---------       
    ---> | val: va | ---> | val: vb | ---> ?
          ---------        ---------     
    

    变成

          node
           |
           v
          ---------        ---------       
    ---> | val: vb | -+   | val: vb |   -> ?
          ---------   |    ---------   |   
                      |                |
                       ----------------
    

    所以实现就这么简单:

    def deleteNode(node):
        """
        :type node: ListNode
        :rtype: void Do not return anything, modify node in-place instead.
        """
        node.val = node.next.val
        node.next = node.next.next
    

    不需要循环。

    回到您的尝试,请注意函数中的最后一行无效。 node 是您的函数中的一个本地名称,并引用尾部 ListNode 实例,直到您将其设置为 None

    你有这个:

          node
           |
           v
          -----------       
    ---> | val: tail | ---> None 
          ----------- 
    

    node = None 这样做:

          node -> None
           X
           |
           v
          -----------       
    ---> | val: tail | ---> None 
          ----------- 
    

    来自前一个节点的传入引用仍然存在

    一旦循环完成,您必须跟踪“one-but-last”节点引用并清除其上的 .next 属性:

    while node.next:
        node.val = node.next.val
        prev, node = node, node.next
    
    # clear reference to tail
    prev.next = None
    

    【讨论】:

    • 是的,你说得对,我做的工作比需要的多,你能看看我的代码吗,我想我确实清理了尾巴,但尾巴仍然让我感到困惑。
    • @o-o: node = None 只设置本地名称。前一个节点中的引用不受影响。
    • 你让它变得如此简单。很好的答案
    【解决方案2】:
    def deleteNode(node):
       node.val = node.next.val
       node.next = node.next.next
    

    由于您没有对当前节点的引用,因此无法删除它。 但是您确实有下一个节点的参考。 所以给你当前的节点你的下一个节点之前的角色, 然后垃圾收集器将删除您的下一个节点,因为您覆盖了 node.next,因此没有剩下任何引用。

    【讨论】:

      猜你喜欢
      • 2016-05-19
      • 2021-09-05
      • 1970-01-01
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      相关资源
      最近更新 更多