Leetcode 中 ListNode 的 Python 逻辑

Python Logic of ListNode in Leetcode

提问人:user6703592 提问时间:6/9/2019 最后编辑:user6703592 更新时间:6/22/2021 访问量:85169

问:

以下是 class 的定义:ListNoteLeetCode

class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

对于代码:

result = ListNode(0)
#result = 0 -> None
result_tail = result
#result_tail = 0 -> None
result_tail.next = ListNode(1)
#result_tail = 0 -> 1 -> None
#result = 0 -> 1 -> None
result_tail = result_tail.next
#result_tail = 1 -> None
#result = 0 -> 1 -> None
result_tail.next = ListNode(2)
#result_tail = 1 -> 2 -> None
#result = 0 -> 1 -> 2 -> None
result_tail = result_tail.next
#result_tail = 2 -> None
#result = 0 -> 1 -> 2 -> None

评论中的值来自我的猜测。我看不懂这一步

result_tail = result_tail.next

result_tail = result是引用传递的,所以当成为时,也应该成为。为什么仍然保留?而当变成 时,为什么会把尾巴伸到?result_tail1 -> Noneresult1 -> Noneresult0 -> 1 -> Noneresult_tail1 -> 2 -> Noneresult0 -> 1 -> 2 -> None

result_tail = result_tail.next

是这样的

result_tail = result.next.next    

谁能告诉我这里的逻辑?

python 链表

评论


答:

25赞 Joseph 12/26/2019 #1

对此的简短回答是,Python 是一种按对象引用传递的语言,而不是问题中暗示的按引用传递。这意味着:

  1. result并且是恰好指向相同值的两个变量result_tail
  2. 基础值 () 的突变/更改将影响result_tail.next = ListNode(1)result
  3. 但是,将变量赋值/指向另一个值不会影响result_tailresult
  4. result_tail = result_tail.next正在分配当前由变量分配的节点的下一个节点

以下是分配给变量 ( = , = ) 的值的可视化效果:rresultrtresult_tail

result = ListNode(0)
#r
#0 -> None

result_tail = result
#r
#0 -> None
#rt

result_tail.next = ListNode(1)
#r
#0 -> 1 -> None
#rt

result_tail = result_tail.next
#r
#0 -> 1 -> None
#     rt

result_tail.next = ListNode(2)
#r
#0 -> 1 -> 2 -> None
#     rt

result_tail = result_tail.next
#r
#0 -> 1 -> 2 -> None
#          rt

其他阅读的参考资料:

4赞 Linlin 8/2/2020 #2

首先,非常感谢您发布这个问题。我处理了同样的问题,看到了这段代码,也感到困惑。然后我听从了 leetcode 的一些评论并来到了这里。

我意识到我的问题是我之前没有笔和纸。我顺着循环在纸上画了链表后,结果发现很清楚。

如果您仍然不清楚这一点,请尝试按照逻辑绘制链表。不确定我在这里是否得到了正确的术语,但以下是我的理解。

老实说,我不认为这与通过引用或值传递有关。对我来说,这只是在开始时为两个变量分配了相同的值(内存位置)。将变量视为地址的存储。地址是真正的内存位置,它是某个值的开始。后来,一个变量(result_tail)不断被重新分配到不同的位置,而一个变量(结果)保持不变。

Result 和 result_tail 都指向 0|while 循环之前没有。
成长为,然后,最后由result_tail.next每次被分配。Result_tail被重新分配,因此值在每个循环中都发生了变化,但结果指向相同的位置,即结果。
0|None0->7|None0->7->0|None0->7->0->8|None0->....

评论

1赞 Coder 12/26/2020
同意,我点击了 leetcode.com/problems/add-two-numbers 的相同链接,谢谢!
13赞 Neeglug 5/9/2021 #3

对于那些将来阅读本文的人:我想在本地环境中调试链表问题,所以这是我所做的。

  1. 修改了 ListNode 的 Leetcode 代码,包含 dunder “repr” 方法。这适用于要打印 ListNode 以查看其值和下一个节点的情况。
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

    def __repr__(self):
        return "ListNode(val=" + str(self.val) + ", next={" + str(self.next) + "})"
  1. 接下来,我制作了一个递归函数,当你传入一个列表时,它会创建一个嵌套的 ListNode。这样你就可以通过传入列表来测试你的方法(而不必自己手动制作一个看起来令人困惑的 ListNode。
def list_to_LL(arr):
    if len(arr) < 1:
        return None

    if len(arr) == 1:
        return ListNode(arr[0])
    return ListNode(arr[0], next=list_to_LL(arr[1:]))
  1. 下面是一个示例,用于测试我对“reverseList”问题的回答:
def reverseList(head: ListNode) -> ListNode:
    prev = None
    while head:
        next_node = head.next
        head.next = prev
        prev = head
        head = next_node

    return prev


# test cases
t1 = list_to_LL([1, 2, 3, 4, 5])  #ListNode(val=1, next={ListNode(val=2, next={ListNode(val=3, next={ListNode(val=4, next={ListNode(val=5, next={None})})})})})
t2 = list_to_LL([1, 2])  #ListNode(val=1, next={ListNode(val=2, next={None})})
t3 = list_to_LL([])

# answers
print(reverseList(t1))
print(reverseList(t2))
print(reverseList(t3))
3赞 nihal dixit 6/21/2021 #4

以上所有答案似乎都不错。我只是举个例子供读者理解。

输入给出:[[1,4,5],[1,3,4],[2,6]]

ListNode 对象说明:

[ListNode{val: 1, next: ListNode{val: 4, next: ListNode{val: 5, next: None}}}, ListNode{val: 1, next: ListNode{val: 3, next: ListNode{val: 4, next: None}}}, ListNode{val: 2, next: ListNode{val: 6, next: None}}]

希望你得到了 CRUX!