# Python - 深夜数据结构与算法之 Recursion

90 篇文章 15 订阅
27 篇文章 1 订阅
16 篇文章 0 订阅

1.Recursion 递归

2.Factorial 阶乘

3.Template 模版

1.Generate-Parentheses [22]

2.Climbing-Stairs [70]

3.Is-Valid-BST [98]

4.Max-Depth [104]

5.Construct-Binary-Tree [105]

6.Min-Depth [111]

7.Invert-Tree [226]

8.Ser-And-Deset-Binary-Tree [297]

9.Low-Common-Ancestor [236]

## 二.递归的简介

### 3.Template 模版

◆ terminator - 终止条件，避免死循环，调用递归时一定要想好停止或者退出的边界条件

◆ process - 处理逻辑，每层递归的处理逻辑

◆ drill donw - 向下钻，很形象，其实就是到更深的一层继续探索，n -> n+1

◆ reverse state - 一些情况下需要保持该层的状态，此时需要再递归结束后进行恢复

Tips:

## 三.经典算法实战

### 1.Generate-Parentheses [22]

class Solution(object):
def generateParenthesis(self, n):
"""
:type n: int
:rtype: List[str]
"""
# 保存结果
result = []
self.generate(0, 0, n, "", result)

return result

def generate(self, left, right, n, s, result):
if left == n and right == n:
result.append(s)

# 保证最左边一定是 '('
if left < n:
self.generate(left + 1, right, n, s + "(", result)

# right 不够就补充
if right < left:
self.generate(left, right + 1, n, s + ")", result)

terminator - len(left) = len(right) && s.start_with('(')

process - s + '('  || s + ')'

drill donw - left + 1 || right + 1

recerse state - 没有全局变量改动，所以无需操作

### 2.Climbing-Stairs [70]

f(n) = f(n-1) + f(n-2)

class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
# 终止条件
if n <= 2:
return n

# 下一层
return self.climbStairs(n-1) + self.climbStairs(n-2)

class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""

if n <= 2:
return n

a, b, c = 1, 2, 3
# 滑动数组
for i in range(3, n):
a, b, c = b, c, b+c

return c

### 3.Is-Valid-BST [98]

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

class Solution(object):

pre = -999999999999999

def isValidBST(self, root):
# 停止条件
if root is None:
return True

# 遍历左子树
if not self.isValidBST(root.left):
return False

# 上一个值大于等于下一个则为异常
if root.val <= self.pre:
return False
self.pre = root.val

# 遍历右子树
return self.isValidBST(root.right)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):

def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
stack = []
cur = root
pre = None

while cur or stack:
if cur:
stack.append(cur)
cur = cur.left
else:
cur = stack.pop()

# 在中序遍历的基础上添加了顺序的判断
if pre and cur.val <= pre.val:
return False
pre = cur
cur = cur.right
return True

### 4.Max-Depth [104]

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):

def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""

# 停止条件
if not root:
return 0
else:
# 向下出发
left_h = self.maxDepth(root.left)
right_h = self.maxDepth(root.right)

# +1: 根节点
return max(left_h, right_h) + 1

向下遍历，遍历时返回自己位置左右子树较高的层数并加上自己所在层的 1。

### 5.Construct-Binary-Tree [105]

pre -> 根左右 in -> 左根右，根据这个逻辑，我们可以从 preorder 确定全局的 root 节点，根据 root 节点的位置，我们在中序遍历中可以获取其左子树和右子树的长度，对于左右子树而言，其前序和中序遍历的长度是一样的，所以可以向下递归，对左右子树分别寻找 root。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""

# 根据 pre 可以获得根节点
if not preorder and not inorder:
return None

# pre -> 根左右 in -> 左根右
root = TreeNode(preorder[0])

# 获取根节点位置
mid_index = inorder.index(root.val)

root.left = self.buildTree(preorder[1: mid_index + 1], inorder[: mid_index])
root.right = self.buildTree(preorder[mid_index + 1:], inorder[mid_index + 1:])

return root

### 6.Min-Depth [111]

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
def minDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
# 无根 -> 0
if not root:
return 0

# 无孩 -> 1
if not root.left and not root.right:
return 1

# 向下递归
left_height = self.minDepth(root.left)
right_height = self.minDepth(root.right)

# 当一边为空一边不为空时，min(h,r) 会返回1，但此时 root 存在叶节点，所以 l+r+1
# 因为如果有一个为空 其返回为0，不会影响最终结果
if not root.left or not root.right:
return left_height + right_height + 1

return min(right_height, left_height) + 1

### 7.Invert-Tree [226]

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
def invertTree(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""

# 停止条件
if not root:
return None

# 处理 左右交换
root.left, root.right = root.right, root.left

# 向下出发
self.invertTree(root.left)
self.invertTree(root.right)

# 无全局变量修改

return root

### 8.Ser-And-Deset-Binary-Tree [297]

BFS 层序遍历

class Codec:

def serialize(self, root):
"""Encodes a tree to a single string.

:type root: TreeNode
:rtype: str
"""
if not root:
return ""
queue = collections.deque([root])
res = []
while queue:
node = queue.popleft()
if node:
res.append(str(node.val))
queue.append(node.left)
queue.append(node.right)
else:
res.append('None')
return '[' + ','.join(res) + ']'

def deserialize(self, data):
"""Decodes your encoded data to tree.

:type data: str
:rtype: TreeNode
"""
if not data:
return []
dataList = data[1:-1].split(',')
root = TreeNode(int(dataList[0]))
queue = collections.deque([root])
i = 1
while queue:
node = queue.popleft()
if dataList[i] != 'None':
node.left = TreeNode(int(dataList[i]))
queue.append(node.left)
i += 1
if dataList[i] != 'None':
node.right = TreeNode(int(dataList[i]))
queue.append(node.right)
i += 1
return root

class Codec:

def bfs(self, root):
result = []
if root is None:
return
my_queue = [root]
while my_queue:
# 返回列表第一个节点的数据
node = my_queue.pop(0)
result.append(node.val)
if node.left is not None:
my_queue.append(node.left)
if node.right is not None:
my_queue.append(node.right)

return result

def serialize(self, root):
"""Encodes a tree to a single string.

:type root: TreeNode
:rtype: str
"""
result = []
if not root:
return ""
queue = [root]
# BFS 遍历二叉树
while queue:
node = queue.pop(0)
result.append(str(node.val))
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return ",".join(result)

def deserialize(self, data):
"""Decodes your encoded data to tree.

:type data: str
:rtype: TreeNode
"""
if not data:
return

tree = data.split(",")

root = TreeNode(int(tree[0]))
result = [root]

choose = ["l", "r"]

for i in range(1, len(tree)):
parent = int((i - 1) / 2)
c = choose[(i-1) % 2]

if tree[i] != "None":
cur_tree = TreeNode(int(tree[i]))
else:
cur_tree = TreeNode(None)

if c == "l":
result[parent].left = cur_tree
result.append(cur_tree)

if c == "r":
result[parent].right = cur_tree
result.append(cur_tree)

return result[0]

### 9.Low-Common-Ancestor [236]

DFS 遍历

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
# 退出条件: 顶节点没有祖先了，最高就这么高了
if root == None or root == p or root == q:
return root

# 分别到左右子树找 p、q 的 root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)

# 左边没找到，右边找
if not left:
return right
# 右边没找到，左边找
if not right:
return left

return root

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
record = {root: None}
stack = [root]
while stack:
node = stack.pop()
if node.left:
record[node.left] = node
stack.append(node.left)
if node.right:
record[node.right] = node
stack.append(node.right)

# p、q 都找都就可以退出了
if p in record and q in record:
break

# 把 p 的父亲节点都标记
while p:
parent = record[p]
record[p] = True
p = parent

# 从 q 向上找，第一个为 True 的即为公共祖先
while record[q] is not True:
q = record[q]

return q

先通过遍历子树并记录的方法将 p 和 q 的全部父亲节点记录下来，随后标记 p 或者 q 的节点父亲为 True，然后从另一个节点的父亲自下而上寻找，第一个为 True 的就是公共的了。

## 四.总结

• 3
点赞
• 0
收藏
觉得还不错? 一键收藏
• 打赏
• 0
评论
03-27 733
08-31 186
03-02 1379
03-28 243
07-29 529

BIT_666

¥1 ¥2 ¥4 ¥6 ¥10 ¥20

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