剑指Offer面试题39二叉树的深度(以及判断平衡二叉树),面试题40数组中只出现一次的数字

面试题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);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值