给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例 1:
1 2 输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]
示例 2:
1 2 输入:root = [2,1,3] 输出:[2,3,1]
示例 3:
提示:
树中节点数目范围在 [0, 100] 内
-100 <= Node.val <= 100
💡 思路: 本质上还是二叉树的遍历:
递归实现,每个节点递归处理左右子节点
迭代法深度优先(栈)实现
迭代法广度优先(层序遍历,队列)实现
代码(思路一):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn invert_tree (root: Option <Rc<RefCell<TreeNode>>>) -> Option <Rc<RefCell<TreeNode>>> { match root { None => None , Some (root) => { let mut node = root.borrow_mut (); let left = node.left.take (); let right = node.right.take (); node.left = Self ::invert_tree (right); node.right = Self ::invert_tree (left); Some (root.clone ()) } } } }
代码(思路二):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn invert_tree (root: Option <Rc<RefCell<TreeNode>>>) -> Option <Rc<RefCell<TreeNode>>> { let mut stack = vec! [root.clone ()]; while !stack.is_empty () { if let Some (node) = stack.pop ().unwrap () { let (left, right) = (node.borrow ().left.clone (), node.borrow ().right.clone ()); stack.push (right.clone ()); stack.push (left.clone ()); node.borrow_mut ().left = right; node.borrow_mut ().right = left; } } root } }
代码(思路三):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 use std::rc::Rc;use std::cell::RefCell;use std::collections::VecDeque;impl Solution { pub fn invert_tree (root: Option <Rc<RefCell<TreeNode>>>) -> Option <Rc<RefCell<TreeNode>>> { let root = match root { Some (r) => r, None => return None , }; let mut queue = VecDeque::new (); queue.push_back (Rc::clone (&root)); while let Some (node) = queue.pop_front () { let (left, right) = (node.borrow ().left.clone (), node.borrow ().right.clone ()); let mut node_ref = node.borrow_mut (); node_ref.left = right; node_ref.right = left; if let Some (left) = &node_ref.left { queue.push_back (Rc::clone (left)); } if let Some (right) = &node_ref.right { queue.push_back (Rc::clone (right)); } } Some (root) } }
给你一个二叉树的根节点 root , 检查它是否轴对称。
示例 1:
1 2 输入:root = [1,2,2,3,4,4,3] 输出:true
示例 2:
1 2 输入:root = [1,2,2,null,3,null,3] 输出:false
提示:
树中节点数目在范围 [1, 1000] 内
-100 <= Node.val <= 100
进阶: 你可以运用递归和迭代两种方法解决这个问题吗?
💡 思路:
递归法: a. 基本思想 :比较左子树和右子树是否互为镜像 b. 递归条件 : 1. 两个节点都为空 → 对称 2. 一个为空一个不为空 → 不对称 3. 两个节点值不相等 → 不对称 4. 递归检查:左子树的左子树与右子树的右子树 && 左子树的右子树与右子树的左子树
迭代法: a. 使用队列 :将需要比较的节点成对放入队列 b. 比较过程 : 1. 每次从队列中取出两个节点比较 2. 将左节点的左子节点与右节点的右子节点一起入队 3. 将左节点的右子节点与右节点的左子节点一起入队
代码(思路一):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn is_symmetric (root: Option <Rc<RefCell<TreeNode>>>) -> bool { match root { None => true , Some (node) => { let node = node.borrow (); Self ::recursion (&node.left, &node.right) } } } fn recursion ( left: &Option <Rc<RefCell<TreeNode>>>, right: &Option <Rc<RefCell<TreeNode>>> ) -> bool { match (left, right) { (None , None ) => true , (Some (left), Some (right)) => { let l = left.borrow (); let r = right.borrow (); l.val == r.val && Self ::recursion (&l.left, &r.right) && Self ::recursion (&l.right, &r.left) } _ => false , } } }
代码(思路二):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn is_symmetric (root: Option <Rc<RefCell<TreeNode>>>) -> bool { let root = match root { Some (r) => r, None => return true , }; let root = root.borrow (); let mut stack = vec! [(root.left.clone (), root.right.clone ())]; while let Some ((left, right)) = stack.pop () { match (left, right) { (None , None ) => continue , (Some (l), Some (r)) => { let l = l.borrow (); let r = r.borrow (); if l.val != r.val { return false ; } stack.push ((l.left.clone (), r.right.clone ())); stack.push ((l.right.clone (), r.left.clone ())); } _ => return false , } } true } }
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(从第 0 层开始),则该层包含 1~2^h 个节点。
示例 1:
1 2 输入:root = [1,2,3,4,5,6] 输出:6
示例 2:
示例 3:
提示:
树中节点的数目范围是[0, 5 * 10^4]
0 <= Node.val <= 5 * 10^4
题目数据保证输入的树是 完全二叉树
进阶: 遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?
💡 思路:
递归法计数
迭代法(层序遍历)计数
代码(思路一):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn count_nodes (root: Option <Rc<RefCell<TreeNode>>>) -> i32 { Self ::count_nodes_ref (&root) } fn count_nodes_ref (root: &Option <Rc<RefCell<TreeNode>>>) -> i32 { if let Some (r) = root { let node = r.borrow (); 1 + Self ::count_nodes_ref (&node.left) + Self ::count_nodes_ref (&node.right) } else { 0 } } }
代码(思路二):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 use std::rc::Rc;use std::cell::RefCell;use std::collections::VecDeque;impl Solution { pub fn count_nodes (root: Option <Rc<RefCell<TreeNode>>>) -> i32 { let Some (root_node) = root else { return 0 }; let mut queue = VecDeque::new (); queue.push_back (root_node); let mut count = 0 ; while let Some (node) = queue.pop_front () { count += 1 ; let node_ref = node.borrow (); if let Some (left) = node_ref.left.as_ref () { queue.push_back (left.clone ()); } if let Some (right) = node_ref.right.as_ref () { queue.push_back (right.clone ()); } } count } }
进阶(递归解法):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn count_nodes (root: Option <Rc<RefCell<TreeNode>>>) -> i32 { if let Some (node) = root { let left_depth = Self ::compute_depth (node.borrow ().left.clone ()); let right_depth = Self ::compute_depth (node.borrow ().right.clone ()); if left_depth == right_depth { (1 << left_depth) + Self ::count_nodes (node.borrow ().right.clone ()) } else { (1 << right_depth) + Self ::count_nodes (node.borrow ().left.clone ()) } } else { 0 } } fn compute_depth (root: Option <Rc<RefCell<TreeNode>>>) -> i32 { let mut depth = 0 ; let mut current = root; while let Some (node) = current { depth += 1 ; current = node.borrow ().left.clone (); } depth } }
给定一个二叉树,判断它是否是 平衡二叉树
示例 1:
1 2 输入:root = [3,9,20,null,null,15,7] 输出:true
示例 2:
1 2 输入:root = [1,2,2,3,3,null,null,4,4] 输出:false
示例 3:
提示:
树中的节点数在范围 [0, 5000] 内
-10^4 <= Node.val <= 10^4
💡 思路: 平衡二叉树是指对于二叉树中的每一个节点 ,其左子树和右子树的高度差不超过1 。这意味着我们需要:
计算每个节点的左右子树高度
检查它们的高度差是否≤1
递归检查所有子树是否也满足这个条件
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 use std::rc::Rc;use std::cell::RefCell;use std::cmp;impl Solution { pub fn is_balanced (root: Option <Rc<RefCell<TreeNode>>>) -> bool { Self ::check_balanced (&root).is_ok () } fn check_balanced (root: &Option <Rc<RefCell<TreeNode>>>) -> Result <i32 , ()> { match root { None => Ok (0 ), Some (node) => { let left_height = Self ::check_balanced (&node.borrow ().left)?; let right_height = Self ::check_balanced (&node.borrow ().right)?; if (left_height - right_height).abs () > 1 { Err (()) } else { Ok (cmp::max (left_height, right_height) + 1 ) } } } } }
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
示例 1:
1 2 输入:root = [1,2,3,null,5] 输出:["1->2->5","1->3"]
示例 2:
提示:
树中节点的数目在范围 [1, 100] 内
-100 <= Node.val <= 100
💡 思路:
遍历二叉树,根节点到叶子节点 → DFS
DFS递归实现: a. 确定递归参数:函数需要当前节点,当前路径 - 1(不包含当前节点的路径),结果集作为参数,无返回值 b. 确定返回条件:当左右子节点都为空时,当前节点为叶子节点,保存当前路径到结果集中,并回溯 到上一层 c. 确定单层递归逻辑:分别判断左右子节点是否为空,同时递归左右子节点
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn binary_tree_paths (root: Option <Rc<RefCell<TreeNode>>>) -> Vec <String > { let mut res = Vec ::new (); Self ::recursion (root.as_ref ().unwrap (), String ::from ("" ), &mut res); res } fn recursion (node: &Rc<RefCell<TreeNode>>, mut path: String , res: &mut Vec <String >) { let node = node.borrow (); if path.is_empty () { path.push_str (&node.val.to_string ()); } else { path.push_str (&format! ("->{}" , &node.val.to_string ())); } if node.left.is_none () && node.right.is_none () { res.push (path); return ; } if let Some (left) = &node.left { Self ::recursion (left, path.clone (), res); } if let Some (right) = &node.right { Self ::recursion (right, path, res); } } }
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
1 2 输入:p = [1,2,3], q = [1,2,3] 输出:true
示例 2:
1 2 输入:p = [1,2], q = [1,null,2] 输出:false
示例 3:
1 2 输入:p = [1,2,1], q = [1,1,2] 输出:false
提示:
两棵树上的节点数目都在范围 [0, 100] 内
-10^4 <= Node.val <= 10^4
💡 思路 :递归判断对应节点是否相同
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn is_same_tree ( p: Option <Rc<RefCell<TreeNode>>>, q: Option <Rc<RefCell<TreeNode>>> ) -> bool { match (p, q) { (None , None ) => true , (Some (p), Some (q)) => { let p = p.borrow (); let q = q.borrow (); p.val == q.val && Self ::is_same_tree (p.left.clone (), q.left.clone ()) && Self ::is_same_tree (p.right.clone (), q.right.clone ()) } _ => false , } } }
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
示例 1:
1 2 输入:root = [3,4,5,1,2], subRoot = [4,1,2] 输出:true
示例 2:
1 2 输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2] 输出:false
提示:
root 树上的节点数量范围是 [1, 2000]
subRoot 树上的节点数量范围是 [1, 1000]
-10^4 <= root.val <= 10^4
-10^4 <= subRoot.val <= 10^4
💡 思路 :前面已经有判断两颗树是否相同:100. 相同的树 , 我们只需要遍历root树判断两颗树是否相同即可
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 use std::cell::RefCell;use std::rc::Rc;impl Solution { pub fn is_subtree ( root: Option <Rc<RefCell<TreeNode>>>, sub_root: Option <Rc<RefCell<TreeNode>>> ) -> bool { Self ::is_subtree_ref (&root, &sub_root) } fn is_subtree_ref ( root: &Option <Rc<RefCell<TreeNode>>>, sub_root: &Option <Rc<RefCell<TreeNode>>> ) -> bool { match (root, sub_root) { (_, None ) => true , (None , _) => false , (Some (root_node), Some (sub_root_node)) => { Self ::same_tree_ref (root, sub_root) || Self ::is_subtree_ref (&root_node.borrow ().left, sub_root) || Self ::is_subtree_ref (&root_node.borrow ().right, sub_root) } } } fn same_tree_ref ( t1: &Option <Rc<RefCell<TreeNode>>>, t2: &Option <Rc<RefCell<TreeNode>>> ) -> bool { match (t1, t2) { (None , None ) => true , (Some (t1), Some (t2)) => { let t1 = t1.borrow (); let t2 = t2.borrow (); t1.val == t2.val && Self ::same_tree_ref (&t1.left, &t2.left) && Self ::same_tree_ref (&t1.right, &t2.right) } _ => false , } } }
给定二叉树的根节点 root ,返回所有左叶子之和。
示例 1:
1 2 3 输入: root = [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
示例 2:
提示:
节点数在 [1, 1000] 范围内
-1000 <= Node.val <= 1000
💡 思路:递归法 将整棵树的左叶子求和分解 为先求节点的左叶子值再求和 因为一个节点是不是左叶子,需要通过父节点判断 → 节点为父节点左孩子,且该节点没有左右孩子 。所以,遍历时使用遍历节点判断左孩子是否为叶子节点,是的话获取该叶子节点的值。否则递归遍历节点左孩子,获取左叶子值。最后加上遍历节点右孩子获取的左叶子值。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn sum_of_left_leaves (root: Option <Rc<RefCell<TreeNode>>>) -> i32 { Self ::sum_of_left_leaves_helper (&root) } fn sum_of_left_leaves_helper (node: &Option <Rc<RefCell<TreeNode>>>) -> i32 { match node { None => 0 , Some (r) => { let node = r.borrow (); let left_sum = if let Some (left) = &node.left { let left_node = left.borrow (); if left_node.left.is_none () && left_node.right.is_none () { left_node.val } else { Self ::sum_of_left_leaves_helper (&node.left) } } else { 0 }; left_sum + Self ::sum_of_left_leaves_helper (&node.right) } } } }
可以看到以上函数在处理左叶子时的逻辑十分繁琐,我们可以优化一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn sum_of_left_leaves (root: Option <Rc<RefCell<TreeNode>>>) -> i32 { Self ::sum_of_left_leaves_helper (&root, false ) } fn sum_of_left_leaves_helper (node: &Option <Rc<RefCell<TreeNode>>>, is_left: bool ) -> i32 { match node { None => 0 , Some (n) => { let node = n.borrow (); if is_left && node.left.is_none () && node.right.is_none () { return node.val; } Self ::sum_of_left_leaves_helper (&node.left, true ) + Self ::sum_of_left_leaves_helper (&node.right, false ) } } } }
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
示例 1:
示例 2:
1 2 输入:[1,2,3,4,null,5,6,null,null,7] 输出:7
提示:
二叉树的节点个数的范围是 [1,10^4]
-2^31 <= Node.val <= 2^31 - 1
💡 思路:
题目寻找最底层,最左侧数据 → 用层序遍历 获取最后一层最左侧数据即可
递归法: a. 递归到深度最大的叶子节点 b. 怎么找最大深度 → 需要一个变量存储最大深度,当当前深度大于最大深度时更新,且这个最大深度变量不能因递归改变(指的是:只能当满足条件时更新。当变量处于递归里时,每个递归状态中会维护一个递归中的变量,我们要将最大深度放在递归外部,防止递归影响) c. 最大深度更新时同步更新结果(结果同样要放在递归外部)
代码(思路一):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 use std::rc::Rc;use std::cell::RefCell;use std::collections::VecDeque;impl Solution { pub fn find_bottom_left_value (root: Option <Rc<RefCell<TreeNode>>>) -> i32 { if let Some (root) = root { let mut queue = VecDeque::new (); queue.push_back (root); let mut left_v = 0 ; while !queue.is_empty () { let size = queue.len (); for i in 0 ..size { let node = queue.pop_front ().unwrap (); let node = node.borrow (); if i == 0 { left_v = node.val; } if let Some (left) = &node.left { queue.push_back (left.clone ()); } if let Some (right) = &node.right { queue.push_back (right.clone ()); } } } left_v } else { 0 } } }
代码(思路二):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn find_bottom_left_value (root: Option <Rc<RefCell<TreeNode>>>) -> i32 { let mut res = 0 ; let mut max_depth = 0 ; Self ::recur (&root, 1 , &mut max_depth, &mut res); res } fn recur (node: &Option <Rc<RefCell<TreeNode>>>, depth: i32 , max_depth: &mut i32 , res: &mut i32 ) { if let Some (n) = node { let node = n.borrow (); if depth > *max_depth { *max_depth = depth; *res = node.val; } Self ::recur (&node.left, depth + 1 , max_depth, res); Self ::recur (&node.right, depth + 1 , max_depth, res); } } }
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
示例 1:
1 2 3 输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 输出:true 解释:等于目标和的根节点到叶节点路径如上图所示。
示例 2:
1 2 3 4 5 6 输入:root = [1,2,3], targetSum = 5 输出:false 解释:树中存在两条根节点到叶子节点的路径: (1 --> 2): 和为 3 (1 --> 3): 和为 4 不存在 sum = 5 的根节点到叶子节点的路径。
示例 3:
1 2 3 输入:root = [], targetSum = 0 输出:false 解释:由于树是空的,所以不存在根节点到叶子节点的路径。
提示:
树中节点的数目在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
💡 思路 :递归,进行DFS,当路径和为题目要求的时,返回true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn has_path_sum (root: Option <Rc<RefCell<TreeNode>>>, target_sum: i32 ) -> bool { Self ::recur (&root, target_sum) } fn recur (node: &Option <Rc<RefCell<TreeNode>>>, target_sum: i32 ) -> bool { if let Some (node) = node { let node = node.borrow (); if node.left.is_none () && node.right.is_none () { node.val == target_sum } else { Self ::recur (&node.left, target_sum - node.val) || Self ::recur (&node.right, target_sum - node.val) } } else { false } } }
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
示例 1:
1 2 输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 输出:[[5,4,11,2],[5,8,4,5]]
示例 2:
1 2 输入:root = [1,2,3], targetSum = 5 输出:[]
示例 3:
1 2 输入:root = [1,2], targetSum = 0 输出:[]
提示:
树中节点总数在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
💡 思路 :递归,使用DFS进行记录路径,当且仅当节点为叶子几点,节点路径值之和满足条件时,记录路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn path_sum (root: Option <Rc<RefCell<TreeNode>>>, target_sum: i32 ) -> Vec <Vec <i32 >> { let mut res = vec! []; let mut path = vec! []; Self ::dfs (&root, target_sum, &mut path, &mut res); res } fn dfs ( node: &Option <Rc<RefCell<TreeNode>>>, target_sum: i32 , path: &mut Vec <i32 >, res: &mut Vec <Vec <i32 >> ) { if let Some (node) = node { let node = node.borrow (); path.push (node.val); let remaining = target_sum - node.val; if node.left.is_none () && node.right.is_none () { if remaining == 0 { res.push (path.clone ()); } } else { Self ::dfs (&node.left, remaining, path, res); Self ::dfs (&node.right, remaining, path, res); } path.pop (); } } }
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
示例 1:
1 2 输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
示例 2:
1 2 输入:inorder = [-1], postorder = [-1] 输出:[-1]
提示:
1 <= inorder.length <= 3000
postorder.length == inorder.length
-1000 <= inorder[i], postorder[i] <= 3000
inorder 和 postorder 都由 不同 的值组成
postorder 中每一个值都在 inorder 中
inorder 保证 是树的中序遍历
postorder 保证 是树的后序遍历
💡 思路:
后序遍历特点 :最后一个元素是根节点
中序遍历特点 :根节点左侧是左子树,右侧是右子树
递归构建 : a. 从后序确定根节点 b. 在中序中找到根节点位置 c. 划分左右子树 d. 递归构建左右子树
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn build_tree (inorder: Vec <i32 >, postorder: Vec <i32 >) -> Option <Rc<RefCell<TreeNode>>> { Self ::build_helper (&inorder, &postorder) } fn build_helper (inorder: &[i32 ], postorder: &[i32 ]) -> Option <Rc<RefCell<TreeNode>>> { if inorder.is_empty () { return None ; } let root_val = *postorder.last ().unwrap (); let root = Rc::new (RefCell::new (TreeNode::new (root_val))); if postorder.len () == 1 { return Some (root); } let root_pos = inorder.iter ().position (|&x| x == root_val).unwrap (); let inorder_left = &inorder[..root_pos]; let inorder_right = &inorder[root_pos + 1 ..]; let postorder_left = &postorder[..root_pos]; let postorder_right = &postorder[root_pos..postorder.len () - 1 ]; root.borrow_mut ().left = Self ::build_helper (inorder_left, postorder_left); root.borrow_mut ().right = Self ::build_helper (inorder_right, postorder_right); Some (root) } }
可以看到在每次递归中都循环查找位置(第3步),可以优化一下,使用哈希表可以达到O(1)的查找效率。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 use std::rc::Rc;use std::cell::RefCell;use std::collections::HashMap;impl Solution { pub fn build_tree (inorder: Vec <i32 >, postorder: Vec <i32 >) -> Option <Rc<RefCell<TreeNode>>> { let index_map : HashMap<_, _> = inorder .iter () .enumerate () .map (|(i, &val)| (val, i)) .collect (); Self ::build_helper (&inorder[..], &postorder[..], &index_map) } fn build_helper ( inorder: &[i32 ], postorder: &[i32 ], index_map: &HashMap<i32 , usize > ) -> Option <Rc<RefCell<TreeNode>>> { if inorder.is_empty () { return None ; } let root_val = *postorder.last ().unwrap (); let root_pos = index_map[&root_val] - index_map[&inorder[0 ]]; let mut root = Rc::new (RefCell::new (TreeNode::new (root_val))); if postorder.len () == 1 { return Some (root); } let inorder_left = &inorder[..root_pos]; let inorder_right = &inorder[root_pos + 1 ..]; let postorder_left = &postorder[..root_pos]; let postorder_right = &postorder[root_pos..postorder.len () - 1 ]; root.borrow_mut ().left = Self ::build_helper (inorder_left, postorder_left, index_map); root.borrow_mut ().right = Self ::build_helper (inorder_right, postorder_right, index_map); Some (root) } }
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历 , inorder 是同一棵树的中序遍历 ,请构造二叉树并返回其根节点。
示例 1:
1 2 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]
示例 2:
1 2 输入: preorder = [-1], inorder = [-1] 输出: [-1]
提示:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder 和 inorder 均 无重复 元素
inorder 均出现在 preorder
preorder 保证 为二叉树的前序遍历序列
inorder 保证 为二叉树的中序遍历序列
💡 思路 :同106. 从中序与后序遍历序列构造二叉树
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 use std::rc::Rc;use std::cell::RefCell;use std::collections::HashMap;impl Solution { pub fn build_tree (preorder: Vec <i32 >, inorder: Vec <i32 >) -> Option <Rc<RefCell<TreeNode>>> { let index_map : HashMap<i32 , usize > = inorder.iter ().enumerate ().map (|(i, &v)| (v, i)).collect (); Self ::build_helper (&preorder, &inorder, &index_map) } fn build_helper ( preorder: &[i32 ], inorder: &[i32 ], index_map: &HashMap<i32 , usize > )-> Option <Rc<RefCell<TreeNode>>>{ if preorder.is_empty () { return None ; } let root_val = *preorder.first ().unwrap (); let root_node = Rc::new (RefCell::new (TreeNode::new (root_val))); if preorder.len () == 1 { return Some (root_node); } let root_pos = index_map[&root_val] - index_map[&inorder[0 ]]; root_node.borrow_mut ().left = Self ::build_helper ( &preorder[1 ..root_pos + 1 ], &inorder[..root_pos], index_map ); root_node.borrow_mut ().right = Self ::build_helper ( &preorder[root_pos + 1 ..], &inorder[root_pos + 1 ..], index_map ); Some (root_node) } }
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 12 输入:nums = [3,2,1,6,0,5] 输出:[6,3,5,null,2,0,null,null,1] 解释:递归调用如下所示: - [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。 - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。 - 空数组,无子节点。 - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。 - 空数组,无子节点。 - 只有一个元素,所以子节点是一个值为 1 的节点。 - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。 - 只有一个元素,所以子节点是一个值为 0 的节点。 - 空数组,无子节点。
示例 2:
1 2 输入:nums = [3,2,1] 输出:[3,null,2,null,1]
提示:
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
nums 中的所有整数 互不相同
💡 思路 :看题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 use std::rc::Rc;use std::cell::RefCell;impl Solution { pub fn construct_maximum_binary_tree (nums: Vec <i32 >) -> Option <Rc<RefCell<TreeNode>>> { Self ::construct_helper (&nums) } fn construct_helper (nums: &[i32 ]) -> Option <Rc<RefCell<TreeNode>>> { if nums.is_empty () { return None ; } let mut max = nums[0 ]; let mut index_max = 0 ; for i in 1 ..nums.len () { if nums[i] > max { max = nums[i]; index_max = i; } } let root = Rc::new (RefCell::new (TreeNode::new (max))); if nums.len () == 1 { return Some (root); } root.borrow_mut ().left = Self ::construct_helper (&nums[..index_max]); root.borrow_mut ().right = Self ::construct_helper (&nums[index_max + 1 ..]); Some (root) } }