概要
本篇介绍一下关于二叉树结构很基础的面试题,基础到什么程度呢,引用谷歌的话术: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so f*** off.(连二叉树翻转你都不会,你还玩个毛!)进一步说明了学习数据结构与算法的重要性——为了不被谷歌鄙视-.-
华为面试题——将二叉树的两个孩子换位置,即左变右,右变左。不能用递规。
原题
226. Invert Binary Tree(Easy)
Invert a binary tree.
Example:
Input:
Output:
Trivia:
This problem was inspired by this original tweet by Max Howell:
Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so f*** off.
226. 翻转二叉树 (简单)
翻转一棵二叉树。
示例:
输入:
输出:
备注:
这个问题是受到 Max Howell 的原问题启发:
谷歌:
我们谷歌90%的工程师使用你写的软件(Homebrew),但是你却无法在面试时在白板上写出翻转二叉树这道题,这...(连二叉树翻转你都不会,你还玩个毛!)
- 分类:树(tree)
分析
理解递归思想的条件下很容易想到解题思路,当然可能有人会有疑问,那什么情况下知道使用递归呢,有个最简单的办法如果算法里需要重复循环用同一个思路执行得到结果,那么必然可以使用递归。进行翻转本质上可以拆分为两步递归,递归翻转左子树和递归翻转右子树分。无论是否使用递归本质思想是一致的,使用非递归的方式则需要借助使用栈或者队列的结构进行存储未交换的子节点。
思路设计
方法一:循环,栈存储(DFS,非递归)
本质思想是,左右节点进行交换,循环翻转每个节点的左右子节点,将未翻转的子节点存入栈中,循环直到栈里所有节点都循环交换完为止。方法一伪代码:
方法二:循环,队列存储(BFS,非递归)
本质思想是,左右节点进行交换,循环翻转每个节点的左右子节点,将未翻转的子节点存入队列中,循环直到栈里所有节点都循环交换完为止。
- 方法一、方法二伪代码:
1、判断根结点是否为空,为空则返回null;
2、新建栈(队列),用于节点存储,初始存入根节点到栈(队列)里;
3、while循环,栈(队列)为空时结束循环;
i.出栈(队列)一个节点,将该节点的左右子节点交互;
ii.判断左右子节点是否为null,非null则继续将左右节点入栈(队列);
4、循环交换结束,返回根节点;
方法三:递归
本质思想也是左右节点进行交换,交换前递归调用对根结点的左右节点分别进行处理,保证交换前左右节点已经翻转。
- 方法三伪代码:
1、判断根结点是否为空,为空则返回null;
2、交换跟节点的左右节点;
3、递归交互左右子树;
编码实践
栈实现
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()) {
final TreeNode node = stack.pop();
final TreeNode left = node.left;
node.left = node.right;
node.right = left;
if(node.left != null) {
stack.push(node.left);
}
if(node.right != null) {
stack.push(node.right);
}
}
return root;
}
队列实现
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
TreeNode left = node.left;
node.left = node.right;
node.right = left;
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
return root;
}
递归实现
public TreeNode invertTree(TreeNode node) {
if (node == null) {
return null;
}
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
invertTree(node.left);
invertTree(node.right);
return node;
}
彩蛋
对比三种实现代码执行结果会发现,三种方法最终leetcode测评的效率都是100%,但是方法一的runtime时间确实1ms,而方法二和方法三的runtime却是0ms。为什么同样的算法思想使用不同的数据结构,使用Stack比使用LinkedList要慢呢?这便是本篇的彩蛋!
结语
华为面试题中的二叉树翻转使用非递归实现是一道基础知识题,二叉树的左右子节点翻转的非递归实现也包含了DFS和BFS的使用,最后如果觉得本篇对你有所帮助,给个赞吧0.0~