[剑指Offer]26~29
[剑指Offer]26~29
学习使用工具
剑指Offer http://itmyhome.com/sword-means-offer/sword-means-offer.pdf
LeetCode的剑指Offer题库 https://leetcode.cn/problemset/all/
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:
3
/ \
4 5
/ \
1 2
给定的树 B:
4
/
1
返回 true
,因为 B 与 A 的一个子树拥有相同的结构和节点值。
示例 1:
输入:A = [1,2,3], B = [3,1]
输出:false
示例 2:
输入:A = [3,4,5,1,2], B = [4,1]
输出:true
限制:
0 <= 节点个数 <= 10000
解法:
写两个递归。一个dfs,用于判断子树是否匹配;一个递归遍历A,当遍历到和B根节点val相等的节点时,调用dfs进行递归判定。整体不难,但是两层思路刚拿到题的时候不是很好捋清。
def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
if not (A and B):
return False
def dfs(A: TreeNode, B: TreeNode):
if not B:
return True
if not A:
return False
if not A.val == B.val:
return False
else:
return dfs(A.left, B.left) and dfs(A.right, B.right)
def travel(A: TreeNode, B: TreeNode):
if not A:
return False
if A.val == B.val:
if dfs(A, B):
return True
return travel(A.left, B) or travel(A.right, B)
return travel(A, B)
剑指 Offer 27. 二叉树的镜像
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/ \
2 7
/ \ / \
1 3 6 9
镜像输出:
4
/ \
7 2
/ \ / \
9 6 3 1
示例:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
限制:
0 <= 节点个数 <= 1000
解法:
递归。先递归,再交换。
def mirrorTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
temp = self.mirrorTree(root.left)
root.left = self.mirrorTree(root.right)
root.right = temp
return root
剑指 Offer 28. 对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/ \
2 2
/ \ / \
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/ \
2 2
\ \
3 3
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
限制:
0 <= 节点个数 <= 1000
解法:
递归。在递归中,当p和q都为空时,返回真;当p和q其中有一个为空,或者val值不相等时,返回假;当p和q的val值相等时,分别判断p的左子树与q的右子树是否相等、p的右子树与q的左子树是否相等。
def isSymmetric(self, root: TreeNode) -> bool:
def check(p: TreeNode, q: TreeNode):
if not (p or q):
return True
if not (p and q):
return False
if not p.val == q.val:
return False
return check(p.left, q.right) and check(p.right, q.left)
return check(root, root)
剑指 Offer 29. 顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
限制:
0 <= matrix.length <= 100
0 <= matrix[i].length <= 100
解法:
虽然这题标着Easy但我感觉不是很简单啊!一翻在主站是算中等的,为啥啊!想了很久也改了半天。
思路:
- 每一圈的遍历方向变化是固定的(先向右,再向下,再向左,再向上)
- 设定四个方向的边界,每次改变方向时,刚刚被遍历的边界收束(向中心移动)
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if not matrix or not matrix[0]: # 判空
return []
# 初始化边界条件
u = 0
d = len(matrix)
l = 0
r = len(matrix[0])
num = 0 # 计数
max = len(matrix) * len(matrix[0]) # 元素总数
ans = [0] * max # 初始化结果数组
while num < max :# 当计数值已经到达元素总数时,break
for i in range(l, r):# 沿着上边界,从左向右将元素加入结果数组
ans[num] = matrix[u][i]
num += 1
u += 1 # 上边界下移
if num == max :
break
for i in range(u, d):# 沿着右边界,从上向下将元素加入结果数组
ans[num] = matrix[i][r - 1]
num += 1
r -= 1 # 右边界左移
if num == max :
break
for i in range(r - 1, l - 1, -1):# 沿着下边界,从右向左将元素加入结果数组
ans[num] = matrix[d - 1][i]
num += 1
d -= 1 # 下边界上移
if num == max :
break
for i in range(d - 1, u - 1, -1):# 沿着左边界,从下向上将元素加入结果数组
ans[num] = matrix[i][l]
num += 1
l += 1
if num == max :
break
return ans