数据结构100题 刷题记录 Python

博主分享了在刷LeetCode数据结构题目的过程中遇到的典型问题和解决方案,包括函数嵌套、闭包、错误处理等。并详细讨论了如何解决二叉树、链表、栈、队列等相关问题,涉及递归、层次遍历等算法。
摘要由CSDN通过智能技术生成

遇到的错误和解决方案:

1.函数嵌套函数

2. 调用函数返没有返回值 return  

3.函数调用函数中间的参数的传递和全局变量和局部变量的问题

解决:函数的闭包问题

闭:指的是定义在函数内部的函数
注意:作用域关系在函数定义阶段就规定死了,与调用位置无关
闭包函数:定义在函数内部的函数,并且该函数包含对外部函数作用域中名字的引用,该函数就称为闭包函数

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

函数嵌套与闭包函数 - 鲁之敬 - 博客园 (cnblogs.com)

Python闭包函数的使用和原理 - 腾讯云开发者社区-腾讯云 (tencent.com)

def first():
    res = []
    def second():
        res.append(1)
    second()
    print( res)
first()

#means

def first():
    res = []
    def second():
        res.append(1)
    second()
    return res
x = first()
print(x)
#第六题
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

#
class Solution:
    def printListFromTailToHead(self , listNode: ListNode) -> List[int]:
        # write code here
        res = []
        if not listNode:
            print(3)
            return res
        
        def traverse(root):
            if not root:
                return res
#             if root.next == None:
#                 res.append(root.val)
#                 print(2,res)
#                 return res  //注意:在函数中如果用了上一层函数的变量,nonlocal类型的变量,那就是直接对上一层函数的进行修改,不能用return ,不然只能得到空
            if root.next:
                traverse(root.next)
            res.append(root.val)
            print(1,res)
        
        traverse(listNode)
        return res //在最后直接输出就好,不用从上面使用 res=traverse(listNode)获得

 4.调用函数

不带括号:只是赋值而没有启动函数

带括号:赋值并且函数

def bar():
    print('from bar')
f = bar()
# from bar

def bar():
    print('from bar')
f = bar
f()
# from bar


def bar():
    print('from bar')
f = bar
# 没有输出 

 带传参

 5.TypeError: descriptor 'append' for 'list' objects doesn't apply to a 'int' object

并没有看明白这是啥问题

题目:

五:替换空格: 从后向前看,从末尾一开始计算好要移动的位置

六:从尾到头打印 :

        1.利用栈分析 从头到尾把数据加入到栈中,再利用pop输出元素

        2.利用递归写 

 递归类似与栈,栈的深度是一定的,如果数据很多就会超过栈的深度

七:做题老是会遇到一种情况,要保留第一次循环的结果,比如第七题,需要保留root的内容最后输出,(或者构建出树之后在从后往前输出?)

~~~怎么处理每一个节点

~~~怎么处理叶子节点~~

一开始

class Solution:
    def reConstructBinaryTree(self , pre: List[int], vin: List[int]) -> TreeNode:
        # write code here
        #在pre中找到根节点,然后在vin中根据根节点分成左右子树的vin,再根据分成的左右子树
#         的长度去pre中找同样长度的pre内容
        if len(pre) ==0:
            return 
#         if len(pre) == 1 and len(vin) == 1:
#             return
        root = TreeNode(pre[0])
        print(root.val)
#         输出 1 2 3 然后就停止了,证明是遇到第一个叶子节点的时候返回出错
#         print(root.val)
        root_vinindex = vin.index(pre[0])
#       求左右子树的vin
        leftvin = vin[:root_vinindex]
        rightvin = vin[root_vinindex+1:]
#        求左右子树的长度
        left_length=len(leftvin)
        right_length = len(rightvin)
#         求左右子树的pre
        leftpre = pre[1:left_length+1]
        rightpre = pre[left_length+1:]
        
        print(1,leftpre,2,rightpre)
        print(1.1,leftvin,2.2,rightvin)
        
        root.left = TreeNode(leftpre[0])
        root.right = TreeNode(rightpre[0])
        if len(leftpre)>0:
            self.reConstructBinaryTree(leftpre,leftvin)
        if len(rightpre)>0:
            self.reConstructBinaryTree(rightpre,rightvin)
        return root

首先,原本的思路算不出来,但是通过加一个队列,使用层次遍历的方法,每个节点构建字典,对应它自己的前序和中序,最后读取字典,利用层次遍历一层一层的加左右节点,也许能解决?感觉很麻烦

因为列表长度问题,一个列表如果只有list[0]但是你调用了list[1]就会溢出

我不知道怎么来处理这个最后list[0]的 的情况,然后看了大佬的代码,通过直接

root.left = createfunction()构建函数来解决

再通过if not root :return 来限制叶子节点之下的节点,咱就是说这也太牛了吧wwww

换个思路解决问题

class Solution:
    def reConstructBinaryTree(self , pre: List[int], vin: List[int]) -> TreeNode:
        # write code here
        #在pre中找到根节点,然后在vin中根据根节点分成左右子树的vin,再根据分成的左右子树
#         的长度去pre中找同样长度的pre内容
        if not pre:
            return 
#         if len(pre) == 1 and len(vin) == 1:
#             return
        root = TreeNode(pre[0])
        print(root.val)
#         输出 1 2 3 然后就停止了,证明是遇到第一个叶子节点的时候返回出错
#         print(root.val)
        root_vinindex = vin.index(pre[0])
#       求左右子树的vin
        leftvin = vin[:root_vinindex]
        rightvin = vin[root_vinindex+1:]
#        求左右子树的长度
        left_length=len(leftvin)
        right_length = len(rightvin)
#         求左右子树的pre
        leftpre = pre[1:left_length+1]
        rightpre = pre[left_length+1:]
        
#         print(1,leftpre,2,rightpre)
#         print(1.1,leftvin,2.2,rightvin)
# !!!这一步很厉害哇我靠,通过return 和 直接调用函数的方法构造树
        root.left = self.reConstructBinaryTree(leftpre,leftvin)
        root.right = self.reConstructBinaryTree(rightpre,rightvin)

        return root
        

细想,我的代码和和正确代码最大的区别是

我的代码使用root.left = TreeNode (从子节点前序列表取值构建),是一种从上到下的思想,从上往下把左右节点加到root上

而修改后的代码,是使用递归从下到上的思想,从到达叶子节点的return 开始构建,从下到上 第一层:把叶子节点左右左右节点加到上一层节点,之后的每一层把左右子树加到root节点

发散:在斐波那契数列中也有类似的思想,一开始是从上到下构建数列,然后 第一次修改 利用备忘录记录下可能重读计算的节点,之后再使用到节点的值,第二次修改时想要计算f(n)的斐波那契数列,从下往上计算 f(1)-f(2)---f(n)的方式计算。

发现自己缺:

1.返回值处理的不好

2.循环,递归结束位置处理的不好

第八题:求二叉树的下一个节点

注意:在输入中,看似输入了一个集合和一个Int数字,实则输入一个二叉树和一个节点,只需要直接对节点操作就行,某些时候看似多种情况,列出来还要记得找规律,结合中序遍历的特点

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
        # write code here
        #思想:在自己找到临界值节点做尝试,找到合适的节点,用实例来找下一个节点
#       选择几个特殊节点:8 -- 9 (有右子树 -- 右子树的最左子节点) 6-7 10-11 
#                       5 -- 6 (没有右子树,且为父节点的左子节点 -- 头节点) self.next 9-10
#                       7 -- 8 (没有右子树,且为父节点的右子节点 -- 某一级父节点是左子节点) 
#                       11 -- null 树的最右叶子节点 以上三种情况都不是
# 也就是分为 :有右子树 --- 右子树最左节点
#             没有右子树 --- 是父节点的左子节点 --父节点
#                           是父节点的右子节点 --找父节点(是左子节点)
        if pNode == None:
            return None
#        第二步,找每个节点有什么特殊的地方 ,从节点本身的三个指针来看
        pNext = None
        if pNode.right:
            pcurrent = pNode.right
            while pcurrent.left:
                pcurrent = pcurrent.left
            pNext = pcurrent
        elif pNode.next:
            pcurrent = pNode
            pParent = pNode.next
            while pParent!=None and pcurrent == pParent.right:
#                如果是右子节点,则进入循环,这个地方相当于把两个情况合并,最终都是要找某个父节点
                pcurrent = pParent
                pParent = pParent.next
            pNext = pParent
        return p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值