【问题标题】:Two Identical Tables Yields Different DP results两个相同的表产生不同的 DP 结果
【发布时间】:2021-12-29 21:29:39
【问题描述】:

我正在解决一个 Hackerrank 问题,它只是最长公共子序列的简单实现

tbl = [[0]*(len(s2)+1)] * (len(s1)+1)

# iterate the two strings and update the [i][j] location accordingly
for i in range(len(s1)+1):
    for j in range(len(s2)+1):
        if i == 0 or j == 0: continue # outer row/col indices
        elif s1[i-1] == s2[j-1]:
            tbl[i][j] = tbl[i-1][j-1] + 1
        else:
            tbl[i][j] = max(tbl[i-1][j], tbl[i][j-1])
            
return tbl[len(s1)][len(s2)]

这一直给我错误的答案,即使我知道我正确地实现了算法。

一时兴起,我决定尝试以不同的方式初始化我的表。我发现了以下二维数组初始化:

[[0]*(len(s2)+1) for i in range(len(s1)+1)]

唯一的区别是我不是将外括号乘以len(s)+1,而是通过for 循环进行行扩展。

按下提交,瞧,它接受了答案。

好奇,我把两个tbl的初始化都扔到了python控制台里。

>>> x = [[0]*(len(s2)+1)] * (len(s1)+1)
>>> y = [[0]*(len(s2)+1) for i in range(len(s1)+1)]
>>> x == y
True

这肯定是奇怪的行为。即使将表格内容打印到终端也证明了相同的结构。

>>> for row in x:
...     print(row)
... 
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
>>> for row in y:
...     print(row)
... 
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
[None, None, None, None, None, None, None]
>>> 

有没有人知道是什么导致了这种输出差异?考虑到这可能与它的编译方式有关,我使用 HR 给定测试用例输入 s1 = SHINCHAN; s2 = NOHARAAA 在本地测试了函数,并在我的(损坏的)表 init 和正确的 LCS 为 3 时产生了不正确的 LCS 6我在网上找到的。

【问题讨论】:

    标签: python python-3.x list


    【解决方案1】:

    这是 Python 的经典错误之一。您不能使用* 运算符初始化二维数组,例如x = [[0]*5]*5。原因是这为您提供了一个包含 5 个对 SAME [0,0,0,0,0] 列表的引用的列表,它们不是 5 个独立的列表。如果您更改x[0][3],您也将更改x[1][3]x[2][3]。尝试设置x[2][2] = 9y[2][2] = 9 并注意区别。

    >>> x[2][2] = 9
    >>> y[2][2] = 9
    >>> for row in x:
    ...     print(row)
    ...
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    >>> for row in y:
    ...     print(row)
    ...
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 9, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    

    【讨论】:

    • 啊,我明白了,这是一个列表引用数组。奇怪的是 == 运算符会认为它们相等。即使将其放入 assert() 也不会突出它们的结构差异
    • 默认情况下,== 查看内容。内容相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    相关资源
    最近更新 更多