labuladong系列1

边学习边记笔记~~~
先学一遍,再结合笔记speed复习一遍!!!

刷题回来了
坚持每天至少一题 保持感觉与思维习惯最重要

总指导labuladong

#开篇
明白目标是什么 \textbf{明白目标是什么} 明白目标是什么 可以量化的才叫目标(可拆分)
递归思维:自顶向下 (反向求解) -->动态规划
迭代思维:自底向上
算法只是个tool 先死后生
⋅ \cdot 切记!人的精力是有限的 不断提高效率
目标 - 计划 - 严格执行

题型分类

================分割线 ========================
框架思维
[数据结构和算法]

⋅ \cdot 数据结构的存储方式: 数组(顺序存储) 链表(链式存储)
[队列] [栈]都可用数组和链表实现
数组实现:扩容缩容
链表实现:更多内存空间存储节点指针
⋅ \cdot 矩阵好处:
判断连通性迅速;并可以进行矩阵运算解决一些问题
缺陷:稀疏 很耗空间
⋅ \cdot 「树」,用数组实现就是「堆」
「堆」是一个完全二叉树
⋅ \cdot 数组:紧凑连续存储,可以随机访问
⋅ \cdot 链表:存储空间不连续不能随机访问 ;每个元素必须存储指向前后元素位置的指针

二叉树

只要涉及递归的问题,都是树的问题
动态规划问题 树的遍历
回溯算法 N 叉树的前后序遍历问题

框架-no细节–小结专题

二 叉 树 系 列 开 始 \textcolor{red}{二叉树系列开始} (第一集)

递归
226. 翻转二叉树
在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root: return root		
        left = self.invertTree(root.left)  #先处理单独节点的反转
        right = self.invertTree(root.right)
        root.left, root.right = right, left  #再对节点进行处理
        return root

116. 填充每个节点的下一个右侧节点指针
完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。
在这里插入图片描述

注意:换层直接指向下一层的 节点即可

"""
# Definition for a Node.
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root: return root
		
		#从根节点开始
        leftmost = root
        while leftmost.left:
            #遍历 这一层节点组成的[链表] (用head表示移动),并为下一层节点更新 next指针
            head = leftmost
            while head:
                head.left.next = head.right
                if head.next: 
                    head.right.next = head.next.left

                #(同一层)处理完一个节点,向后移动
                head = head.next
            
            #下一层
            leftmost = leftmost.left
        
        return root

时间复杂度:O(N)O(N),每个节点只访问一次。
空间复杂度:O(1)O(1),不需要存储额外的节点。


* 前序遍历

144. 二叉树的前序遍历
递归

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        #先定义(以每个node处理的函数)
        def preorder(root: TreeNode): #内部函数无须self
            if not root: return    #==里层不受干扰 才能空==
            res.append(root.val)
            preorder(root.left)  #递归下去:走完所有的左子树
            preorder(root.right)  #递归下去:走完所有的右子树
        
        res = list()
        preorder(root)
        return res #==外层一定要有实量==

时间复杂度:O(n),其中 nn 是二叉树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(log n),最坏情况下树呈现链状,为 O(n)。

迭代
显式地将这个栈模拟出来

class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        res = list()
        if not root: return res
        
        #显式给出栈
        stack = []
        node = root
        while stack or node:
            #对于一个node,先走完所有可能的左子树(最左边的结点)
            while node:
                res.append(node.val)
                stack.append(node)
                node = node.left
            #左节点没有了(到底了),吐一个出来; 再移到右(一层一层往上移)
            node = stack.pop()
            node = node.right
        return res

时间复杂度:O(n),其中 nn 是二叉树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为迭代过程中显式栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)。

拓展
前序 中序 后序遍历总结


114. 二叉树展开为链表
在这里插入图片描述
递归

class Solution:
    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        pre = list()

        def preorderTraversal(root: TreeNode):
            if root:
                pre.append(root)  ##`特别注意:return是None 不是T144中的List`,故不能用root.val
                preorderTraversal(root.left)
                preorderTraversal(root.right)

        preorderTraversal(root)
        size = len(pre)
        for i in range(1, size):
            prev, curr = pre[i-1], pre[i]  #
            prev.left = None   #
            prev.right = curr 

时间复杂度:O(n)
空间复杂度:O(n)

如果其左子节点不为空,则在其左子树中找到最右边的节点,作为 前 驱 节 点 \textcolor{blue}{前驱节点}
将 [当前节点的右子节点] 赋给 (前驱节点的右子节点) pre.right = cur.right
然后将[当前节点的左子节点] 赋给当前节点的右子节点 ,并将[当前节点的左子节点] 设为空 cur.right = next
对当前节点处理结束后,继续处理链表中的下一个节点,直到所有节点都处理结束。

进阶解法

class Solution:
	def flatten(self, root: TreeNode) -> None:
		curr =root
        while curr:
			##一层层往下 将最右边树移到 倒数第二右边,然后倒数第三右边...一直到最左边
			#如果`当前节点的左子节点不为空`
            if curr.left:
                pre = nxt = curr.left
				#寻找`前驱节点`
                while pre.right:
                    pre = pre.right
                    
                pre.right = curr.right

                #题目要求 指针
                curr.left = None
                curr.right = nxt
                
            curr = curr.right				

时间复杂度:O(n),其中 nn 是二叉树的节点数。展开为单链表的过程中,需要对每个节点访问一次,在寻找前驱节点的过程中,每个节点最多被额外访问一次。
空间复杂度:O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值