对称二叉树
- https://leetcode.cn/problems/symmetric-tree/
描述
- 给你一个二叉树的根节点 root , 检查它是否轴对称。
示例 1
1
/ | \
2 | 2
/ \ | / \
3 4 | 4 3
中间一条线是对称轴
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2
1
/ \
2 2
\ \
3 3
输入:root = [1,2,2,null,3,null,3]
输出:false
提示
- 树中节点数目在范围 [1, 1000] 内
- -100 <= Node.val <= 100
Typescript 版算法实现
1 )深度优先递归版本
/**
* Definition for a binary tree node.
* class TreeNode {
* val: number
* left: TreeNode | null
* right: TreeNode | null
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
* }
*/
function isSymmetric(root: TreeNode | null): boolean {
if(!root) return true;
const isMirror = (l: TreeNode | null, r: TreeNode | null) => {
if(!l && !r) return true; // 空树是镜像的
return l?.val === r?.val && isMirror(l?.left, r?.right) && isMirror(r?.left, l?.right)
};
return isMirror(root.left, root.right);
}
- 解题思路
- 转化为:左右子树是否镜像
- 分解为:树1的左子树和树2的左子树是否镜像;树1的右子树和树2的左子树是否镜像,成立,且根节点值相同,则镜像
- 符合:分、解、合的特性,考虑分而治之
- 解题步骤
- 分:获取两个树的左子树和右子树
- 解:递归地判断树1的左子树和树2的右子树是否镜像,树1的右子树和树2的左子树是否镜像
- 合:如果上述两个都成立,且根节点值也相同,两个树就是镜像
- 时间复杂度:O(n)
- 叶子节点数量
- 空间复杂度: O(n)
- 堆栈的高度,树的高度
- 最坏情况高度==树节点数
2 )广度优先迭代版本
/**
* Definition for a binary tree node.
* class TreeNode {
* val: number
* left: TreeNode | null
* right: TreeNode | null
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
* }
*/
function isSymmetric(root: TreeNode | null): boolean {
if(!root || (!root.left && !root.right)) return true;
const queue: (TreeNode | null)[] = [root.left, root.right];
while(queue.length) {
const left = queue.shift();
const right = queue.shift();
// 如果两个节点都为空就继续循环,两者有一个为空就返回false
if (!left && !right) continue;
if (!left || !right) return false;
if (left.val !== right.val) return false;
// 将左节点的左孩子, 右节点的右孩子 存入队列
queue.push(left.left);
queue.push(right.right);
// 将左节点的右孩子 和 右节点的左孩子 存入队列
queue.push(left.right);
queue.push(right.left);
}
return true;
}
- 使用广度优先遍历来替代深度优先遍历实现对称校验
- 时间复杂度是 O(n)
- 空间复杂度是 O(n)
扩展
二叉树中,从数组中的数据解析成Tree Node 结构的过程如下
1 )二叉树节点和数组索引(下标)之间的关系,如下
0层 0 2的0次方 = 1 个
/ \
1层 1 2 2的1次方 = 2 个
/ \ / \
2层 3 4 5 6 2的2次方 = 4 个
2 )从数组转换成Tree Node的代码实现过程如下,如下
class TreeNode {
val: number
left: TreeNode | null
right: TreeNode | null
constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
this.val = (val === undefined ? 0 : val)
this.left = (left === undefined ? null : left)
this.right = (right === undefined ? null : right)
}
}
class Tree {
constructor (data) {
// 临时存储所有节点,方便寻找父子节点
const nodeList = [];
for (let i = 0, len = data.length; i < len; i++) {
const node = new TreeNode(data[i]);
nodeList.push(node);
if (i === 0) continue; // 开始层root跳过处理
// 计算当前节点属于那一层
const n = Math.floor(Math.sqrt(i + 1));
// 记录当前层的起始点
const q = Math.pow(2, n) - 1;
// 记录上一层的起始点
const p = Math.pow(2, n - 1) - 1;
// 找到当前节点的父节点
const parent = nodeList[p + Math.floor((i - q) / 2)];
// 将当前节点和上一层的父节点做关联
if (parent.left) {
parent.right = node
} else {
parent.left = node
}
}
const root = nodeList.shift(); // 拿出第一个节点
nodeList.length = 0; // 清空临时节点列表
return root;
}
}
- 从上述关系和代码过程可以看到
- 当前节点(的下标i)与层级n的关系:
const n = Math.floor(Math.sqrt(i + 1)) - 当前层的起点下标:
const q = Math.pow(2, n) - 1 - 上一层的起点下标:
const p = Math.pow(2, n - 1) - 1 - 基于当前节点,找到其父节点:
const parent = nodeList[p + Math.floor((i - q) / 2)]
- 当前节点(的下标i)与层级n的关系:
- 我们如果想到得到从数组转换过来的当前树,只需要执行
const root = new Tree([1, 2, 2, 3, 4, 5, 3])- 第一个数组参数是传入的数据
- 得到的 root 是这棵树的起点,内部已经构建好了节点之间的关系
- 当然,这只是从数组转二叉树的一种广度优先遍历的实现形式
Python3 版算法实现
1 ) 方案1
# 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 isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
def isMirror(l: TreeNode, r: TreeNode) -> bool:
if not l and not r:
return True # 空树是镜像的
if not l or not r:
return False
return l.val == r.val and isMirror(l.left, r.right) and isMirror(l.right, r.left)
return isMirror(root.left, root.right)
2 ) 方案2
# 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 isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root or (not root.left and not root.right):
return True
queue = [root.left, root.right]
while queue:
left = queue.pop(0)
right = queue.pop(0)
# 如果两个节点都为空就继续循环,两者有一个为空就返回false
if not left and not right:
continue
if not left or not right:
return False
if left.val != right.val:
return False
# 将左节点的左孩子, 右节点的右孩子 存入队列
queue.append(left.left)
queue.append(right.right)
# 将左节点的右孩子 和 右节点的左孩子 存入队列
queue.append(left.right)
queue.append(right.left)
return True
Golang 版算法实现
1 ) 方案1
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func isSymmetric(root *TreeNode) bool {
if root == nil {
return true
}
var isMirror func(l *TreeNode, r *TreeNode) bool
isMirror = func(l *TreeNode, r *TreeNode) bool {
if l == nil && r == nil {
return true // 空树是镜像的
}
if l == nil || r == nil {
return false
}
return l.Val == r.Val && isMirror(l.Left, r.Right) && isMirror(l.Right, r.Left)
}
return isMirror(root.Left, root.Right)
}
2 ) 方案2
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func isSymmetric(root *TreeNode) bool {
if root == nil || (root.Left == nil && root.Right == nil) {
return true
}
queue := []*TreeNode{root.Left, root.Right}
for len(queue) > 0 {
left := queue[0]
right := queue[1]
queue = queue[2:]
// 如果两个节点都为空就继续循环,两者有一个为空就返回false
if left == nil && right == nil {
continue
}
if left == nil || right == nil {
return false
}
if left.Val != right.Val {
return false
}
// 将左节点的左孩子, 右节点的右孩子 存入队列
queue = append(queue, left.Left, right.Right)
// 将左节点的右孩子 和 右节点的左孩子 存入队列
queue = append(queue, left.Right, right.Left)
}
return true
}
1295



被折叠的 条评论
为什么被折叠?



