刷刷笔试题~~[二叉树编程]

1.给定一颗二叉树,以及其中的两个node(地址均非空),要求给出这两个node的一个公共父节点,使得这个父节点与两个节点的路径之和最小。描述你程序的最坏时间复杂度,并实现具体函数

C++函数原型:

1
2
3
4
5
6
7
strucy TreeNode{
      TreeNode* left;    //指向左子树
      TreeNode* right;    //指向右子树
      TreeNode* father;    //指向父亲节点
};
TreeNode* LowestCommonAncestor(TreeNode* first,TreeNode* second){
}
解析:

这里给出了父节点指针,难度一下就降下来了

方法一:首先找到两个节点的高度差,然后从较靠近根节点的一层开始向上找,若父节点为同一节点则该节点为解

最坏时间复杂度为O(n)

public class SameFather {
	class Node{
		public Node father;
		public Node left;
		public Node right;
		
	}
	public int getHeight(Node node){
		int h=0;
		while(node!=null){
			h++;
			node=node.father;
		}
		return h;
	}
	public Node LowestCommonAncestor(Node first,Node second){
		int h1=getHeight(first);
		int h2=getHeight(second);
		int diff=h1-h2;
		if(diff<0){//first在上面
			diff=-diff;
			while(diff--!=0){//先判断不为0,之后再减1
				second=second.father;//second往上赶
			}
		}else{
			while(diff--!=0){
				first=first.father;
			}
		}
		while(first!=second){
			first=first.father;
			second=second.father;
		}
		return first;
	}
}


2..二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

解析:

画一个二叉树,求出该二叉树的中序遍历

(1)如果树为空,return null

(2)如果树有右子树,找到右子树最左节点

(3)如果没有右节点,它的下一个节点应该是,以自己为左孩子的父节点,如果自己不是自己父节点的左孩子,就继续向上找


<span style="font-family:Microsoft YaHei;font-size:14px;">/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if(pNode==null)
            return null;
        if(pNode.right!=null){//如果右子树不为空
            pNode=pNode.right;
            if(pNode.left!=null)
                pNode=pNode.left;
            return pNode;
        }
        while(pNode.next!=null){//因为要一直往上找
            if(pNode.next.left==pNode)
                return pNode.next;
            pNode=pNode.next;
        }
        return null;
    }
}</span>

3.对称的二叉树

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

解析:

一看到这种题,就有感觉要用递归来做

判断两个子树是否对称

左子树的左子树应该等于右子树的右子树

左子树的右子树应该等于右子树的左子树


/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        if(pRoot==null)//记得判断为空的情况,这个在递归里面判断不了
            return true;
        return same(pRoot.left,pRoot.right);
    }
    boolean same(TreeNode leftNode,TreeNode rightNode){
        if(leftNode==null&&rightNode!=null)return false;
        if(leftNode!=null&&rightNode==null)return false;
        if(leftNode==null&&rightNode==null)return true;
        if(leftNode.val==rightNode.val)
            return same(leftNode.left,rightNode.right)&&same(leftNode.right,rightNode.left);
        return false;
    }
}


4.按之字形顺序打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

解析:

层次遍历+每一层单行输出,这个是之前做过的题,改编一下

定义两个变量,curNum和nextNum来分别保存当前层的节点数和下一层的节点数

初始化时curNum=1,nextNum=0

层次遍历用队列,先把根节点压入,开始循环

弹出队列头节点,输出,curNum--,判断弹出的节点有没有左右孩子,有的话压入队列,每压入一个,nextNum++

判断if(curNum==0),等于0的话说明,这一行已经遍历完了,curNum=nextNum,nextNum=0;

这里每输出一层,按顺序存放在arrayList中,可以用一个标志位flag,true的时候从左到右,false的时候从右到左,每当curNum==0时转换,

转换之前判断是true还是false,true的话正常把这一次的arraylist加到总的结果中,否则,反转这个arraylist后再添加进去



import java.util.*;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer> > res=new ArrayList<ArrayList<Integer> >();
        if(pRoot==null)//不要忘记判断
            return res;
        int curNum=1;
        int nextNum=0;
        boolean flag=true;
        ArrayList<Integer> list=new ArrayList<Integer>();
        Queue<TreeNode> queue=new LinkedList<TreeNode>();//记得这里是链表,才能生成的队列
        queue.add(pRoot);
        while(!queue.isEmpty()){
            TreeNode node=queue.poll();
            list.add(node.val);
            curNum--;
            if(node.left!=null){
                queue.add(node.left);
                nextNum++;
            }
            if(node.right!=null){
                queue.add(node.right);
                nextNum++;
            }
            if(curNum==0){
                if(flag)
                    res.add(list);
                else{
                    res.add(reverse(list));
                }
                
                flag=!flag;
                curNum=nextNum;
                nextNum=0;
                list=new ArrayList<Integer>();//只有打印完一行才再重新声明
            }
            
        }
        return res;
    }
    public ArrayList<Integer> reverse(ArrayList<Integer> list){
        int len=list.size();
        ArrayList<Integer> list2=new ArrayList<Integer>();
        for(int i=len-1;i>=0;i--){
            list2.add(list.get(i));
        }
        return list2;
    }

}


5.把二叉树打印成多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

解析:这个就是层次遍历按层输出的那个


import java.util.ArrayList;
import java.util.*;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer> > res=new ArrayList<ArrayList<Integer> >();
        if(pRoot==null)
            return res;
        ArrayList<Integer> list=new ArrayList<Integer>();
        Queue<TreeNode> queue=new LinkedList<TreeNode>();
        int curNum=1;
        int nextNum=0;
        queue.add(pRoot);
        while(!queue.isEmpty()){
            TreeNode node=queue.poll();
            list.add(node.val);
            curNum--;
            if(node.left!=null){
                queue.add(node.left);
                nextNum++;
            }
            if(node.right!=null){
                queue.add(node.right);
                nextNum++;
            }
            if(curNum==0){
                res.add(list);
                curNum=nextNum;
                nextNum=0;
                list=new ArrayList<Integer>();
            }
        }
        return res;
    }
    
}


6.序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树

解析:

第一种方法:

序列化二叉树,就是把二叉树变成一串字符串,先序遍历,最开始str="",不停往上面加,最后返回str

每遍历一个节点后面加上!,遇到空节点输出#!

遇到空节点返回#!,先加上根节点!,再对根节点的左孩子调用这个方法,然后对根节点的右孩子调用这个方法,最后返回str,递归

反序列化:对用先序遍历序列化的字符串进行反序列化

用到队列,先把字符串用split("!")变成字符串数组,遍历把每个元素添加到队列中,空的时候返回null,这个在后面的递归中要用到

弹出的第一个节点是根节点,然后根节点的左孩子是队列中剩下的元素调用这个函数得到的节点,遍历到#后,说明当前结点的左孩子后面没有东西了,返回当前结点,看他的右孩子,再遍历到#后,再回到当前结点,找到当前结点的父节点,也使用递归实现

!!注意,因为是递归,所以每轮只算自己的!!不用哪一步都str+=

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    //序列化
    String Serialize(TreeNode root) {
        if(root==null){
            return "#!";//这里return#!就行,不用加上str
        }
        String str=root.val+"!";//每次只算自己的!!
        str+=Serialize(root.left);
        str+=Serialize(root.right);
        return str;
  }
    //反序列化!
    TreeNode Deserialize(String str) {
       Queue<String> queue=new LinkedList<String>();//这里存放的是String类型
       String[] s=str.split("!");
        for(int i=0;i<s.length;i++){
            queue.add(s[i]);
        }
        return reconPre(queue);
  }
    public TreeNode reconPre(Queue<String> queue){
        String value=queue.poll();
        if(value.equals("#"))
            return null;
        TreeNode head=new TreeNode(Integer.valueOf(value));
        head.left=reconPre(queue);
        head.right=reconPre(queue);
        return head;
    }
}


第二种方法:

层次遍历来序列化:序列化的时候要用到队列,序列化的字符串是str,初始时为空

最开始判断是否为空,为空的话return #!

先将节点压入队列,队列是TreeNode类型的,然后层次遍历

先压入头节点,当队列不为空的时候,循环,弹出队首的元素,将val!加入到str中,

看看这个节点有没有左孩子右孩子,有的话分别压入队列,没有的话str+"#!" , 循环,


反序列化:先把字符串split("!")拆成String数组

其实反序列化就相当于再来一遍层次遍历,之前用先序遍历时就相当于再来一遍先序遍历。遇到#,表示是null,其他的就是正常节点

声明一个队列,TreeNode类型的,把String数组中第一个数放进去,然后index++,队列不为空的时候循环

取出队首元素,通过一个函数把它变成节点,然后按理来说后面两个是它的左右孩子,判断一下是不是空节点,是的话不要管了,

是正常节点的话以左孩子或者右孩子的身份添加到队列中

思路一定要清晰!!

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    String Serialize(TreeNode root) {
        Queue<TreeNode> queue=new LinkedList<TreeNode>();
        if(root==null)
            return "#!";
        String str=root.val+"!";
        queue.add(root);
        while(!queue.isEmpty()){
            root=queue.poll();
            if(root.left!=null){
                str+=root.left.val+"!";
                queue.add(root.left);
            }else{
                str+="#!";
            }
            if(root.right!=null){
                str+=root.right.val+"!";
                queue.add(root.right);
            }else{
                str+="#!";
            }
        }
        return str;
  }
    TreeNode Deserialize(String str) {
        String[] s=str.split("!");
        Queue<TreeNode> queue=new LinkedList<TreeNode>();
        int index=0;//指针在数组中移动
        TreeNode head=createNode(s[index++]);
        if(head!=null){
            queue.add(head);
        }
        TreeNode node=null;//这个node要放在外面,因为里面一直用一个
        while(!queue.isEmpty()){
            node=queue.poll();
            node.left=createNode(s[index++]);
            node.right=createNode(s[index++]);
            if(node.left!=null){
                queue.add(node.left);
            }
            if(node.right!=null){
                queue.add(node.right);
            }
            
        }
        return head;
  }
    public TreeNode createNode(String a){
        if(a.equals("#"))
            return null;
        return new TreeNode(Integer.valueOf(a));
    }
}


7.二叉搜索树的第k个结点

给定一颗二叉搜索树,请找出其中的第k小的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。

解析:

中序遍历,存到数组里,取出第k-1个


/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    ArrayList<TreeNode> list=new ArrayList<TreeNode>();
    public void inorder(TreeNode node){
        if(node==null)
            return ;
        inorder(node.left);
        list.add(node);
        inorder(node.right);
        
    }
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        inorder(pRoot);
        if(k>list.size()||k<=0)
        	return null;
        return list.get(k-1);
    }
    


}


8.

二叉树的深度

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

解析:

递归求解:
假如是空节点,则返回0;
否则,原树的深度由左右子树中深度较的深度加1,为原树的深度。

/*
public class TreeNode {
	int val = 0;
	TreeNode left = null;
	TreeNode right = null;
	public TreeNode(int val) {
        this.val = val;
    }
};*/
public class Solution {
	public int TreeDepth(TreeNode pRoot)
    {
        if(pRoot==null)
            return 0;
        return Math.max(1+TreeDepth(pRoot.left),1+TreeDepth(pRoot.right));
    }
}


9.平衡二叉树

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

/*
 * 输入一棵二叉树,判断该二叉树是否是平衡二叉树
 */
public class BalanceTree {
	class TreeNode{
		TreeNode left;
		TreeNode right;
	}
	//声明了一个全局变量来判断是否是平衡树
	private boolean isBalanced=true;
    public boolean IsBalanced_Solution(TreeNode root) {
        getDepth(root);
        return isBalanced;
    }
    //这个函数其实是在求树的高度
    public int getDepth(TreeNode root){
    	if(root==null)//递归到底部的时候
    		return 0;
    	int left=getDepth(root.left);//递归来求树的高度,递归就相当于自底向上了
    	int right=getDepth(root.right);
    	//每次求完子树的高度,就判断一下
    	if(Math.abs(left-right)>1)
    		isBalanced=false;//不是记为false,但无论如何都要遍历一遍,最后把isBalanced输出来
    	return right>left?right+1:left+1;
    }
}


/*
 * 输入一棵二叉树,判断该二叉树是否是平衡二叉树
 */

public class BalanceTree2 {
	class TreeNode{
		TreeNode left;
		TreeNode right;
	}
	//这里用了一个class来传值,声明对象后就可以根据对象来保存这个值n
	//这里n其实相当于树的深度
	private class Holder{
		int n;
	}
	public boolean IsBalanced_Solution(TreeNode root){
		return judge(root,new Holder());
	}
	public boolean judge(TreeNode root,Holder h){
		if(root==null)
			return true;
		Holder l=new Holder();
		Holder r=new Holder();
		//这边的两个judge是在递归,先跑到树的最下面
		//如果最下面的两个子数都是平衡树,那就判断一下他俩的高度差
		if(judge(root.left,l)&&judge(root.right,r)){
			if(Math.abs(l.n-r.n)>1)
				return false;
			h.n+=(l.n>r.n?l.n:r.n)+1;
			return true;
		}
		return false;
	}
}







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值