面试题39:二叉树的深度(以及判断平衡二叉树)
思路:二叉树的深度可以用递归去求,首先如果只有根节点,深度为1,如果根节点只有一个子树,深度为子树的深度+1,如果有两个子树,深度为两个子树的深度较大值加+1。
至于判断平衡二叉树的思路:有了上边求深度的方法后,马上可以想到去遍历树节点,对其子树调用求深度的函数,如果每个结点的左右子树的深度相差都不超过1,就是平衡二叉树。但是这种方法会重复遍历结点,效率太低。
我们可以用后序遍历的方法遍历所有结点,这样在遍历一个结点之前我们就已经遍历了它的左右子树,只要在遍历每个结点时记录它的深度,就可以达到一边遍历一边判断每个结点手否平衡,详见代码。
Java实现如下:
class BiTree{
int data;
BiTree left;
BiTree right;
}
public class TreePath {
//递归求树的深度
static int treePath(BiTree root){
if(root == null)
return 0;
int left = treePath(root.left);
int right = treePath(root.right);
return left > right ? (left+1) : (right+1);
}
// 因为java基本类型参数是值传递,无法记录每个子树的深度,所以用一个类来做参数。
static class Depth{
int n;
}
//判断平衡二叉树
static boolean isBalanced(BiTree root){
Depth depth = new Depth();
return isBalanced(root, depth);
}
static boolean isBalanced(BiTree root, Depth depth){
if(root == null){
depth.n = 0;
return true;
}
Depth left = new Depth();
Depth right = new Depth();
if(isBalanced(root.left, left) && isBalanced(root.right, right)){
int diff = left.n - right.n;
if(diff <= 1 && diff >= -1){
depth.n = 1 + (left.n > right.n ? left.n : right.n);
return true;
}
}
return false;
}
public static void main(String[] args) {
BiTree node1 = new BiTree();
BiTree node2 = new BiTree();
BiTree node3 = new BiTree();
BiTree node4 = new BiTree();
BiTree node5 = new BiTree();
node1.left = node2;
node1.right = node3;
node2.left = node4;
node4.left = node5;
System.out.println(treePath(node1));
System.out.println(isBalanced(node1));
}
}
关于Java的参数传递,可以看这篇文章:
java参数传递的方式
面试题40:数组中只出现一次的数字
一个数组中除了两个数字之外,其它数字都出现了两次,找出这两个数。例如输入数组{2,4,3,6,3,2,5,5},因为只有4、6两个数字只出现一次,其它都出现了两次,所以输出4、6。
思路:这题比较偏,利用异或运算的性质,任何一个数异或它自己都等于0,如果从头到尾依次异或数组中的每一个数字,那么最终结果刚好是哪个只出现一次的数字,因为成对出现的数字全部在异或中抵消了。
具体的,如果能够把原数组分为两个子数组,在每个子数组中,包含一个只出现一次的数字,而其它数字都出现两次。如果能够这样拆分原数组,按照前面的办法就是分别求出这两个只出现一次的数字了。我们还是从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。由于这两个数字肯定不一样,那么这个异或结果肯定不为0,也就是说在这个结果的二进制表示中至少有一位为1。我们在结果数字中找到第一个为1的位的位置,记为第N位。现在我们以第N位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0。现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其它数字都出现了两次。
Java实现如下:
public class FindNumsAppearOnce {
public void findNumsAppearOnce(int[] array){
if(array == null)
return ;
int number = 0;
for(int i : array)
number ^= i;
int index = findFirstBitIs1(number);
int number1 = 0;
int number2 = 0;
for(int i : array){
if(isBit1(i,index))
number1 ^= i;
else
number2 ^= i;
}
System.out.println(number1);
System.out.println(number2);
}
//找到number二进制表示中最右边1所在位置
private int findFirstBitIs1(int number){
int indexBit = 0;
while((number & 1) == 0){
number = number >> 1;
indexBit++;
}
return indexBit;
}
//判断在number的二进制表示中从右边数起的index位是不是1
private boolean isBit1(int number,int index){
number = number >> index;
return (number & 1) == 0;
}
public static void main(String args[]){
FindNumsAppearOnce test = new FindNumsAppearOnce();
int[] array = {2,4,3,6,3,2,5,5};
test.findNumsAppearOnce(array);
}
}