Skip to content

Commit d7847a4

Browse files
committed
leetcode
1 parent 17dfb22 commit d7847a4

9 files changed

Lines changed: 170 additions & 6 deletions

File tree

5.LeetCode/101.symmetric-tree/1.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
随后 p 右移时,q 左移;p 左移时,q 右移。每次检查当前 p 和 q 节点的值是否相等,如果相等再继续判断左右子树是否对称。
1212
1313
14-
时间复杂度:渐进时间复杂度为 O(n),其中 n 为二叉树节点的个数。每个节点在递归中只被遍历一次。
15-
空间复杂度:和递归使用的栈空间有关,这里递归层数不超过 n,渐进空间复杂度为 O(n)。
14+
时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点在递归中只被遍历一次。
15+
空间复杂度:O(h),其中 h 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(n)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(logn)。
1616
"""
1717

1818

5.LeetCode/101.symmetric-tree/2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1010
1111
时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点只会被访问一次。
12-
空间复杂度:这里需要用一个队列来维护节点,每个节点最多进队一次,出队一次,队列中最多不会超过 n 个点,故渐进空间复杂度为 O(n)。
12+
空间复杂度:取决于队列中存储的最大元素个数,其在最坏情况下会达到 O(n)。
1313
"""
1414

1515

5.LeetCode/104.maximum-depth-of-binary-tree/1.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
1919
2020
时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点在递归中只被遍历一次。
21-
空间复杂度:O(h),其中 h 表示二叉树的高度。递归函数需要函数栈空间,而栈空间取决于递归的深度,因此空间复杂度等于二叉树的高度
21+
空间复杂度:O(h),其中 h 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(n)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(logn)
2222
"""
2323

2424

5.LeetCode/104.maximum-depth-of-binary-tree/2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
2323
2424
时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点在递归中只被遍历一次。
25-
空间复杂度:O(height),其中 height 表示二叉树的高度。递归函数需要栈空间,而栈空间取决于递归的深度,因此空间复杂度等价于二叉树的高度
25+
空间复杂度:O(h),其中 h 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(n)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(logn)
2626
"""
2727

2828

5.LeetCode/112.path-sum/4.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
1616
if not root:
1717
return False
1818

19-
def _dfs(root: TreeNode, full_path: list[int]) -> bool:
19+
def _dfs(root: TreeNode, full_path: List[int]) -> bool:
2020
if not root: # 叶子节点的左右子节点都是 None,递归退出条件
2121
return False
2222
if not root.left and not root.right and sum(full_path) == targetSum: # leaf node. 注意:只有叶子节点才判断 full_path 求和后是否等于 targetSum
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
方法一: 深度优先搜索(DFS) - 递归
3+
https://leetcode-cn.com/leetbook/read/data-structure-binary-tree/xefb4e/
4+
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/tu-jie-er-cha-shu-de-si-chong-bian-li-by-z1m/
5+
6+
解题思路:
7+
什么是二叉树的前序遍历:按照访问「根节点、左子树、右子树」的方式遍历这棵树,
8+
而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。
9+
因此整个遍历过程天然具有递归的性质,我们可以直接用递归函数来模拟这一过程
10+
11+
12+
时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点在递归中只被遍历一次。
13+
空间复杂度:O(h),其中 h 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(n)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(logn)。
14+
"""
15+
16+
17+
# Definition for a binary tree node.
18+
# class TreeNode:
19+
# def __init__(self, val=0, left=None, right=None):
20+
# self.val = val
21+
# self.left = left
22+
# self.right = right
23+
class Solution:
24+
def preorderTraversal(self, root: TreeNode) -> List[int]:
25+
def _dfs(root: TreeNode):
26+
if not root:
27+
return
28+
res.append(root.val)
29+
_dfs(root.left)
30+
_dfs(root.right)
31+
32+
res = []
33+
_dfs(root)
34+
return res
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
方法二: 迭代
3+
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/tu-jie-er-cha-shu-de-si-chong-bian-li-by-z1m/
4+
5+
解题思路:
6+
使用栈来进行迭代,由于栈是 "后进先出" 的顺序,所以入栈时先将右子树入栈,这样使得前序遍历结果为「根、左、右」的顺序。过程如下:
7+
1. 初始化栈,并将根节点入栈
8+
2. 当栈不为空时:
9+
(1) 弹出栈顶元素 cur,并将它的值添加到结果中
10+
(2) 如果 cur 的右子节点非空,将右子节点入栈
11+
(3) 如果 cur 的左子节点非空,将左子节点入栈
12+
13+
14+
时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点只会被遍历一次。
15+
空间复杂度:取决于栈中存储的最大元素个数,其在最坏情况下会达到 O(n)。
16+
"""
17+
18+
19+
# Definition for a binary tree node.
20+
# class TreeNode:
21+
# def __init__(self, val=0, left=None, right=None):
22+
# self.val = val
23+
# self.left = left
24+
# self.right = right
25+
class Solution:
26+
def preorderTraversal(self, root: TreeNode) -> List[int]:
27+
res = []
28+
if not root:
29+
return res
30+
31+
stack = [root] # 创建栈,根节点入栈
32+
while stack:
33+
cur = stack.pop() # 弹出栈顶元素
34+
if cur:
35+
res.append(cur.val) # 将栈顶元素的值添加到结果中
36+
if cur.right:
37+
stack.append(cur.right) # 右子节点入栈
38+
if cur.left:
39+
stack.append(cur.left) # 左子节点入栈
40+
41+
return res
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
方法三: 迭代
3+
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/tu-jie-er-cha-shu-de-si-chong-bian-li-by-z1m/
4+
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/er-cha-shu-de-qian-xu-bian-li-by-leetcode-solution/
5+
6+
解题思路:
7+
使用「显示栈」来模拟递归中维护的「隐式系统栈」,由于栈是 "后进先出" 的顺序,所以入栈时先将右子树入栈,这样使得前序遍历结果为「根、左、右」的顺序。过程如下:
8+
1. 初始化栈
9+
2. cur 指向根节点,将它的值添加到结果中,将它压栈(目的是后续将它出栈时能获取右子节点)
10+
3. 如果 cur 有左子节点,将 cur 重新指向左子节点。重复步骤 2 (使用 while 循环),直到 cur 为 None
11+
4. 当 cur 为 None 时,弹出栈顶元素,并用 cur 重新指向它。获取它的右子节点,然后用 cur 重新指向右子节点。重复步骤 2 和 3 (使用另一个 while 循环),直到栈为空
12+
13+
14+
时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点只会被遍历一次。
15+
空间复杂度:取决于栈中存储的最大元素个数,其在最坏情况下会达到 O(n)。
16+
"""
17+
18+
19+
# Definition for a binary tree node.
20+
# class TreeNode:
21+
# def __init__(self, val=0, left=None, right=None):
22+
# self.val = val
23+
# self.left = left
24+
# self.right = right
25+
class Solution:
26+
def preorderTraversal(self, root: TreeNode) -> List[int]:
27+
res = []
28+
if not root:
29+
return res
30+
31+
stack = [] # 创建栈
32+
cur = root # 开始时,cur 指向根节点
33+
while stack or cur: # 需要加 or cur,因为一开始 stack 就是空的,但此时 cur 不为 None
34+
while cur:
35+
res.append(cur.val) # 将 cur 的值添加到结果中
36+
stack.append(cur) # 将 cur 压栈,目的是后续将它出栈时能获取右子节点
37+
cur = cur.left
38+
cur = stack.pop() # 当 cur 为 None 时,弹出栈顶元素,并用 cur 重新指向它
39+
cur = cur.right # 然后用 cur 重新指向它的右子节点
40+
41+
return res
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
方法四: Morris 遍历
3+
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/er-cha-shu-de-qian-xu-bian-li-by-leetcode-solution/
4+
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/leetcodesuan-fa-xiu-lian-dong-hua-yan-shi-xbian-2/
5+
6+
解题思路:
7+
利用二叉树中大量指向 None 的指针,可以将空间复杂度降为 O(1)
8+
对于给定的二叉树(包括它的左右子树),从根结点开始,找到它的左子树中「最右侧节点 p2」与这个根结点进行连接 (p2.right = p1)。
9+
如果这么连接之后,p1 指针就可以完整的顺着一个节点到下一个节点,将整棵树遍历完毕,直到整棵树的最右侧节点 (p2.right = None)
10+
11+
12+
时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点只会被遍历一次。
13+
空间复杂度:O(1)。
14+
"""
15+
16+
17+
# Definition for a binary tree node.
18+
# class TreeNode:
19+
# def __init__(self, val=0, left=None, right=None):
20+
# self.val = val
21+
# self.left = left
22+
# self.right = right
23+
class Solution:
24+
def preorderTraversal(self, root: TreeNode) -> List[int]:
25+
res = []
26+
if not root:
27+
return res
28+
29+
p1 = root
30+
while p1:
31+
p2 = p1.left
32+
if p2:
33+
while p2.right and p2.right != p1: # 1. 找到它的左子树中「最右侧节点」
34+
p2 = p2.right
35+
36+
if not p2.right:
37+
res.append(p1.val)
38+
p2.right = p1 # 2. 与根结点进行连接
39+
p1 = p1.left
40+
continue
41+
else:
42+
p2.right = None # 3. 断开与根结点的连接,恢复二叉树
43+
else: # p1 没有左子节点时
44+
res.append(p1.val)
45+
46+
p1 = p1.right # p1 顺序往右移动,直到整棵树的最右侧节点
47+
48+
return res

0 commit comments

Comments
 (0)