我在查看面试问题时,最近遇到了一个问题,问如何反转一般的二叉树,就像将其从右侧翻转到左侧。
例如,如果我们有以下二叉树:
6
/ \
3 4
/ \ / \
7 3 8 1
反转它将创建
6
/ \
4 3
/ \ / \
1 8 3 7
你可以看到,新树是原始树的镜像。
我一直想不出如何解决这个问题的好方法。有人能提供任何好的想法吗?
我在查看面试问题时,最近遇到了一个问题,问如何反转一般的二叉树,就像将其从右侧翻转到左侧。
例如,如果我们有以下二叉树:
6
/ \
3 4
/ \ / \
7 3 8 1
反转它将创建
6
/ \
4 3
/ \ / \
1 8 3 7
你可以看到,新树是原始树的镜像。
我一直想不出如何解决这个问题的好方法。有人能提供任何好的想法吗?
您可以使用递归。我们将一个节点的左右子节点就地交换,然后对其子节点执行相同的操作:
static void reverseTree(final TreeNode root) {
final TreeNode temp = root.right;
root.right = root.left;
root.left = temp;
if (root.left != null) {
reverseTree(root.left);
}
if (root.right != null) {
reverseTree(root.right);
}
}
为了处理参数root
可能为null的情况:static void reverseTree(final TreeNode root) {
if (root == null) {
return;
}
final TreeNode temp = root.right;
root.right = root.left;
root.left = temp;
reverseTree(root.left);
reverseTree(root.right);
}
在C/C++中以O(1)的时间复杂度翻转一棵二叉树。
struct NormalNode {
int value;
struct NormalNode *left;
struct NormalNode *right;
};
struct ReversedNode {
int value;
struct ReversedNode *right;
struct ReversedNode *left;
};
struct ReversedNode *reverseTree(struct NormalNode *root) {
return (struct ReversedNode *)root;
}
这个问题有几个有趣的部分。首先,由于您使用的是Java语言,您最有可能拥有一个通用的Node 类,类似于以下内容:
class Node<T> {
private final T data;
private final Node left;
private final Node right;
public Node<T>(final T data, final Node left, final Node right) {
this.data = data;
this.left = left;
this.right = right;
}
....
}
其次,反转(有时称为倒置)可以通过改变节点的左右字段来完成,也可以通过创建一个与原始节点完全相同但其左右子节点已被“反转”的新节点来完成。前一种方法在另一个答案中展示,而后一种方法则在此处展示:
class Node<T> {
// See fields and constructor above...
public Node<T> reverse() {
Node<T> newLeftSubtree = right == null ? null : right.reverse();
Node<T> newRightSubtree = left == null ? null : left.reverse();
return Node<T>(data, newLeftSubtree, newRightSubtree);
}
}
不改变数据结构的想法是持久化数据结构背后的一个概念,这些数据结构非常有趣。
new Node(data=data, left=right?.reverse(), right=left?.reverse())
就太棒了,但是Java还没有实现这个功能。我们也可以这样实现:new Node().withData(data).withLeft(right.reverse.......).withRight(left.reverse......)
等等。我最终只是通过使用命名局部变量使reverse
方法更易读。 - Ray Toal递归函数可以非常简单,如下所示:
public Node flipTree(Node node) {
if(node == null) return null;
Node left = flipTree(node.left);
Node right = flipTree(node.right);
node.left = right;
node.right = left;
return node;
}
// helper method
private static void reverseTree(TreeNode<Integer> root) {
reverseTreeNode(root);
}
private static void reverseTreeNode(TreeNode<Integer> node) {
TreeNode<Integer> temp = node.left;
node.left = node.right;
node.right = temp;
if(node.left != null)
reverseTreeNode(node.left);
if(node.right != null)
reverseTreeNode(node.right);
}
import java.util.LinkedList;
import java.util.Queue;
public class InvertBinaryTreeDemo {
public static void main(String[] args) {
// root node
TreeNode<Integer> root = new TreeNode<>(6);
// children of root
root.left = new TreeNode<Integer>(3);
root.right = new TreeNode<Integer>(4);
// grand left children of root
root.left.left = new TreeNode<Integer>(7);
root.left.right = new TreeNode<Integer>(3);
// grand right childrend of root
root.right.left = new TreeNode<Integer>(8);
root.right.right = new TreeNode<Integer>(1);
System.out.println("Before invert");
traverseTree(root);
reverseTree(root);
System.out.println("\nAfter invert");
traverseTree(root);
}
// helper method
private static void reverseTree(TreeNode<Integer> root) {
reverseTreeNode(root);
}
private static void reverseTreeNode(TreeNode<Integer> node) {
TreeNode<Integer> temp = node.left;
node.left = node.right;
node.right = temp;
if(node.left != null)
reverseTreeNode(node.left);
if(node.right != null)
reverseTreeNode(node.right);
}
// helper method for traverse
private static void traverseTree(TreeNode<Integer> root) {
Queue<Integer> leftChildren = new LinkedList<>();
Queue<Integer> rightChildren = new LinkedList<>();
traverseTreeNode(root, leftChildren, rightChildren);
System.out.println("Tree;\n*****");
System.out.printf("%3d\n", root.value);
int count = 0;
int div = 0;
while(!(leftChildren.isEmpty() && rightChildren.isEmpty())) {
System.out.printf("%3d\t%3d\t", leftChildren.poll(), rightChildren.poll());
count += 2;
div++;
if( (double)count == (Math.pow(2, div))) {
System.out.println();
count = 0;
}
}
System.out.println();
}
private static void traverseTreeNode(TreeNode<Integer> node, Queue<Integer> leftChildren, Queue<Integer> rightChildren) {
if(node.left != null)
leftChildren.offer(node.left.value);
if(node.right != null)
rightChildren.offer(node.right.value);
if(node.left != null) {
traverseTreeNode(node.left, leftChildren, rightChildren);
}
if(node.right != null) {
traverseTreeNode(node.right, leftChildren, rightChildren);
}
}
private static class TreeNode<E extends Comparable<E>> {
protected E value;
protected TreeNode<E> left;
protected TreeNode<E> right;
public TreeNode(E value) {
this.value = value;
this.left = null;
this.right = null;
}
}
}
Before invert
Tree;
*****
6
3 4
7 3 8 1
After invert
Tree;
*****
6
4 3
1 8 3 7
我看到大多数答案都没有关注空指针问题。
public static Node invertBinaryTree(Node node) {
if(node != null) {
Node temp = node.getLeftChild();
node.setLeftChild(node.getRightChild());
node.setRigthChild(temp);
if(node.left!=null) {
invertBinaryTree(node.getLeftChild());
}
if(node.right !=null) {
invertBinaryTree(node.getRightChild());
}
}
return node;
}