python deepcopy函数_那些年用python踩的坑

1.拷贝、引用

执行下面的代码的结果如下:

class Solution:

    def rotate(self, matrix):
        """
        Do not return anything, modify matrix in-place instead.
        """
        n = len(matrix)
        temp = [[0]*n for _ in range(n)]
        #temp = matrix
        #temp = copy.deepcopy(matrix)
        print(temp, matrix)
        matrix = temp[:]
        print(temp,matrix)
x = [[1,2,3],[4,5,6],[7,8,9]]
Solution().rotate(x)
print(x)

e0f83f3b1f924cc4e2a1148c9602bf7f.png

matrix = temp[:] 修改为 matrix[:] = temp

239118fa7e8a94fb5870e97ed61da0a4.png

错误的原因:在调用函数时,传递给形参的是实参matrix的地址,用后一种切片复制,可以根据这个地址对实参进行原地修改;而如果用前一种,函数里的matrix就不再是实参的地址了,而是matrix_new的一个引用,即使修改了,也不会影响实参。

执行下面的代码:

class Solution:

    def rotate(self, matrix):
        """
        Do not return anything, modify matrix in-place instead.
        """
        n = len(matrix)
        #temp = [[0]*n for _ in range(n)]
        temp = matrix[:]
        #temp = copy.deepcopy(matrix)

        print(temp, matrix)
        temp[0][0] = 0
        print(temp,matrix)
x = [[1,2,3],[4,5,6],[7,8,9]]
Solution().rotate(x)
print(x)

490b9d775954092938815714d9676961.png

按理说temp是matrix的拷贝,不应该出现matrix同时被更改的情形啊?这个就是浅层拷贝的问题。

将 temp = matrix[:] 改成 temp = copy.deepcopy(matrix),结果如下

597cc081b01d828c5081f3917276dcc8.png

最后对比一下

temp = [[1]*n for _ in range(n)] 和 temp = [[1]*n]*n

420aaccad7648b809665cad7f6df9277.png

3650a68c0c6ead3e935fc5ae7b55632d.png

后面一种会出现莫名奇妙的错误,仅仅执行了 temp[0][0]=0 。原因在于,因为列表是可变变量,[1,1,1] * 3 后是3个地址一样的[1,1,1],并没有创建更多的列表.

详细的可以看这个链接。

python 深入理解 赋值、引用、拷贝、作用域 - 江召伟 - 博客园​www.cnblogs.com
316f462c9c6b81171981052b8cc9a4af.png

2.关于排序的那些事

        n = len(intercopy)
        for i in range(n):
            for j in range(i+1,n):
                if intercopy[i]>intercopy[j]:
                    intercopy[i],intercopy[j]=intercopy[j],intercopy[i]

上面是冒泡排序,和python 自带的sort 函数做对比,结果耗时差距是2个数量级 。

intercopy.sort(key = lambda x:x[0])

下面一篇文章对10种常见排序做了分析,还有动图。

十大经典排序算法(动图演示) - 一像素 - 博客园​www.cnblogs.com
c0c99af18120b4ed2edf965231fdca8a.png

下面一篇则是对sort排序算法详细分析(timesort的)

python sort函数内部实现原理​www.cnblogs.com
b8a397eca23c4628d355f489601ccf70.png

看完以后,默默删除了自己写的冒泡算法。

3.二叉树

今天刷leetcode二叉树,遇到一个超时的问题。解题思路用的是中序遍历。

class Solution:
    def convertBiNode(self, root: TreeNode) -> TreeNode:
        def judge(root: TreeNode) -> (TreeNode,TreeNode):
            begin=end=root
            if root:
                if root.left:
                    begin,end = judge(root.left)
                    #end.left = None # 这句话没什么用,因为返回的end必然没有子节点
                    end.right = root
                    end = root
                    root.left = None # 这句话必须要有,root的左子节点必须修改
                if root.right:
                    root.right,end = judge(root.right)
            return begin,end
        return judge(root)[0]

上面#注释的2句话,仔细分析了一下,发现第二句话必须加上去,第一句话是无效操作。

70759430ece5bdadcc508c02553c29b7.png
class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root: return None
        #dummy = Node() #位置2
        p = root
        while p:
            dummy = Node() #位置1
            nextlevel = dummy
            while p:
                if p.left :
                    nextlevel.next = p.left
                    nextlevel = p.left
                if p.right:
                    nextlevel.next = p.right
                    nextlevel = p.right
                p = p.next       
            p = dummy.next
        return root  

如上图和代码块,位置1的这句话如果放在位置2会导致循环出不来,debug之后发现当遍历完树的最下面一层,dummy.next还是会指向最后一层的第一个元素。所以必须初始化,让dummy.next = None

20200724

x = (l+r)//2  #1  l<=r,且是整形
x = l+(r-l)//2 #2

原理上看,两者没有区别。但是第二种在某些语言下(如c)可以防止数据溢出

20200728

在处理将二叉树转换成链表的题目中,遇到一个bug,如果用#2的方式编译会超时,#1则不会。百思不得其解,用同样的测试用例,在本地编译器上运行一遍,结果正确。

错误信息为:Found cycle in the TreeNode。怀疑编译器的版本不一样。

力扣​leetcode-cn.com
class Solution:
    def convertBiNode(self, root: TreeNode) -> TreeNode:
        if not root: return None
        lastp = None
        p = root
        stack = []
        while p or stack:
            while p:
                stack.append(p)
                p = p.left
            p = stack.pop()
            #p.left = None  #1 
            if lastp:
                lastp.left = None  #2
                lastp.right = p
            else:
                res = p
            lastp = p
            p = p.right
        return res

20200730:

今天遇到一个小bug,#1是c语言的写法,自己还没习惯python的写法,#2是正确写法。

class Solution:
    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        if not matrix: return 0
        m,n = len(matrix),len(matrix[0])
        # 遍历整个数组 找出需要计算的行 存入栈
        A = []
        for i in range(m):
            tmp = []
            for j in range(n):
                if i==0:
                    #tmp.append((int)matrix[i][j])  #1
                    tmp.append(int(matrix[i][j]))   #2
                else:
                    if matrix[i][j] == "0":
                        tmp.append(0)
                    else:
                        tmp.append(A[i-1][j]+1)
            A.append(tmp)

20200731:

积累两个二叉树遍历的模版,前序和中序竟然可以统一成一个模版。

前序遍历的模版:

def preorder1(root):
    while root:
        if root.right:
            stack.append(root.right)
        #do something
        if root.left:
            root = root.left
        elif stack:
            root = stack.pop()
        else:
            root = None

前序、中序遍历的统一模版:

def inorderTraversal(self, root: TreeNode) -> List[int]:
    stack = []
    while root or stack:
        while root:
            # do something 前序
            stack.append(root)
            root = root.left
        root = stack.pop()
        # do something 中序
        root = root.right
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值