剑指Offer(38-47)

38.输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

//递归做法
public class Test38 {
    public int TreeDepth(TreeNode root) {
        //到达叶子的子节点,返回上一级,从0开始加
        if (root==null){
            return 0;
        }
        //递归左右子树
        int left = TreeDepth(root.left);
        int right = TreeDepth(root.right);
        //从0开始加,每返回上一级就加一,比较左右子树,返回大的。
        return Math.max(left,right)+1;
    }
}
//思路二:利用树的层次搜索
public class Test38_2 {
    public int TreeDepth(TreeNode root) {
        if (root==null) return 0;
        Queue<TreeNode> queue = new LinkedList();
        queue.offer(root);
        //cur记录访问到当前层的第几个,widtd为当前层的宽度
        int size;
        int deep=0;
        while (!queue.isEmpty()){
            //定义每层的结点数
            size = queue.size();
            //层数增加的条件,当每层结点遍历完后,遍历下一层
            for (int i=0;i<size;i++){
                //root = 推出来的结点
                root = queue.poll();
                if (root.left!=null)queue.offer(root.left);
                if (root.right!=null)queue.offer(root.right);
                System.out.println(size+" ");
            }
            //遍历一层后,deep(深度)加一
            deep++;
        }
        return deep;

    }
}

39.输入一棵二叉树,判断该二叉树是否是平衡二叉树。

是上一题的改编

//平衡二叉树:左右子树也是平衡二叉树,左右子树的高度差小于1
public class Test39 {
    public boolean IsBalanced_Solution(TreeNode root) {

        return deep(root) != -1;
    }
    public int deep(TreeNode root){
        if(root==null)  return 0;
        int left = deep(root.left);
        if (left==-1)   return -1;//判断左子树是不是平衡二叉树
        int right = deep(root.right);
        if (right==-1)  return  -1;//判断右子树是不是平衡二叉树
        //比较高度差,也是上一题的附加步骤
        if (right-left<-1||right-left>1)
            return -1;
        else
            return Math.max(left,right)+1;

    }
}

40.一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

//思路一

//用hash算法,存入hashmap,值为1,如果键存在,值设置为2
public class Test40 {
    //题目给出的:
    //num1,num2分别为长度为1的数组。传出参数
    //将num1[0],num2[0]设置为返回结果
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for (int i=0;i<array.length;i++){
            if (map.containsKey(array[i])){
                map.put(array[i],2);
            }else {
                map.put(array[i],1);
            }
        }
        int j=0;
        for (int i=0;i<array.length;i++){
            if((int)map.get(array[i])==1){
                if (j==0){
                    num1[0] = array[i];
                    j++;
                }else {
                    num2[0] = array[i];
                }
            }
        }
    }

}

//思路二
//1、数组排序
//2、使用栈进行从小到大入栈,一样的则弹出,不一样则入栈
//3、取栈中剩余的元素
public class Test40_2 {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {

    //冒泡排序
    for(int i=0;i<array.length-1;i++){
        for(int j=array.length-1;j>i;j--){
            if (array[j]<array[j-1]){
                swap(array,j-1,j);
            }
        }
    }
    Stack<Integer> stack = new Stack<>();
    for (int i=0;i<array.length;i++){
        if(stack.empty()||stack.peek()!=array[i]){
            stack.push(array[i]);
        }else if (stack.peek() == array[i]){
            stack.pop();
        }
    }
    num1[0] = stack.pop();
    num2[0] = stack.pop();

}
private void swap(int[] array,int i,int j){
    int tem = array[i];
    array[i] = array[j];
    array[j] = tem;
}

}

##41.小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。
###现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?

//利用双指针和滑动窗口,plow和phigh分别指向前后两个数
public class Test41 {
public ArrayList<ArrayList> FindContinuousSequence(int sum) {

    int plow = 1, phigh = 2;
    List<ArrayList<Integer>> result = new ArrayList<>();
    while (plow<phigh){
        //差为一的等差数列,用等差数列求和公式(a0+an)*n/2
        int count = (phigh-plow+1)*(phigh+plow)/2;
        if (count==sum){
            List<Integer> list = new ArrayList<>();
            for (int i=plow;i<=phigh;i++){
                list.add(i);
            }
            result.add((ArrayList)list);
            phigh++; plow++;
        }else if (count>sum){
            plow++;
        }else {
            phigh++;
        }
    }
    return (ArrayList)result;
}

}

##42.输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

//和上一题看似差不多,头一次也是类似的做法,但是上一题是连续的数,这一题没有
//所以上一题用滑动窗口,这一题可以用夹逼,两个指针指向两端并不断逼近
//PS:如果和相同,那么差越大,乘积越小
public class Test42 {
public ArrayList FindNumbersWithSum(int [] array, int sum) {
List result = new ArrayList<>();
if (array.length<2||arraynull){
return (ArrayList)result;
}
int i=0, j=array.length-1;
while (i<j){
int count = array[i]+array[j];
if (count
sum){
result.add(array[i]);
result.add(array[j]);
return (ArrayList)result;
}else if(count<sum){
i++;
}else {
j--;
}
}
return (ArrayList)result;
}
}

posted @ 2020-02-23 20:04  程序员自习室  阅读(116)  评论(0)    收藏  举报