二叉树进阶面试题【3】
前两天有做了几道比较难的二叉树面试题,个人觉得比较锻炼脑子hhh。
1 .给定一个二叉树, 找到该树中两个指定节点的最近公共祖先
1>算法思想
(1)首先考虑特殊情况,如果根节点root为空,则没有祖先可言,返回null。
(2)再考虑如果两个指定节点中有一个是root,那么他们的公共祖先一定是root。
(3)再考虑一般情况
- 如果两个节点一个在左子树,一个在右子树,那么他们的公共祖先一定为root。
- 如果两个节点都在左边,或者都在右边,那么他们的公共祖先一定是他们中最先找到的一个。
2>实现
public TreeNode lowestCommonAncestor(TreeNode root,TreeNode p,TreeNode q){
if(root == null){
return null;
}
if(root == p || root == q ){
return root;
}
TreeNode leftTree = lowestCommonAncestor(root.left,p,q);
TreeNode rightTree = lowestCommonAncestor(root.right,p,q);
if(leftTree != null && rightTree != null){
return root;
}else if(leftTree != null){
//左边找到
return leftTree;
}else if(rightTree != null){
return rightTree;
}
return null;
}
2.二叉树创建字符串
大概就是这个样子:
1>算法思想
(1)首先还是要考虑到根为空的情况,此时返回即可。
(2)如果跟不为空,因为可以看出输出的结果为先序遍历,所以直接将节点保存到字符串中。
(3)先检查root的左子树是否为空 ,不为空则添加一个左括号,并且对左子树进行遍历,遍历完成后添加右括号。
(4)此时就遍历到最后一个节点,如图43位置,会有两种情况,如果该节点没有右孩子,直接返回到上一个节点即可,如果节点有右孩子,那么在遍历右孩子之前要加上()括号来中断输入和输出之间的映射关系。
(5)接着判断右孩子是否为空,如果为空 直接返回,如果不为空先添加左括号,然后遍历右子树,直到全部遍历完以后添加右括号。
2>实现
//二叉树创建字符串
public void tree2strChild(TreeNode t,StringBuilder sb){
if(t == null){
return;
}
sb.append(t.value);
if(t.left != null){
sb.append("(");
tree2strChild(t.left,sb);
sb.append(")");
}else{
//左右孩子都为空
if(t.right == null){
return;
}else{
sb.append("()");
}
}
if(t.right == null){
return;
}else{
sb.append("(");
tree2strChild(t.right,sb);
sb.append(")");
}
}
public String tree2str(TreeNode t){
StringBuilder sb = new StringBuilder();
tree2strChild(t,sb);
return sb.toString();
}
3.二叉搜索树变成双向链表
1>算法思想
实际上就是将定义一个pcur,先让他递归到左子树的叶子节点,然后改变每一个节点原本的指向即可。
2>图解
3>实现
public void ConvertChild(TreeNode Pcur){
TreeNode prev = null;
if(Pcur == null){
return;
}
ConvertChild(Pcur.left);
Pcur.left = prev; //绑左边
if(prev != null) {
prev.right = Pcur; //绑右边
}
prev = Pcur;
ConvertChild(Pcur.right);
//确定头结点位置
public TreeNode Convert(TreeNode pRootOfTree){
ConvertChild(pRootOfTree);
TreeNode head = pRootOfTree;
while(head != null && head.left != null){
head = head.left;
}
return head;
}
}
4.前中序遍历二叉树
1>算法思想
(1)我们可以通过前序遍历确定根节点,在中序遍历找到根节点,他左边的节点就是他的左子树的值,右边的就是右子树的。
(2)前序遍历按照顺序挨着遍历,然后再在中序遍历找到值左右两边的就是他的左右孩子。由此遍历出一颗完整的二叉树。
2>实现
private int preindex = 0;
public TreeNode build(int[] preorder,
int[] inorder,int inbegin,int inend){
if(inbegin > inend){
//当前树根本没有左子树或者是右子树
return null;
}
//根据前序建立确定根节点
TreeNode root = new TreeNode((char)preorder[preindex]);
//在中序遍历中找到根节点的下标
int rootIndex = indexOfInorder(
inorder,preorder[preindex],inbegin,inend);
preindex ++;
root.left = build(preorder,inorder,inbegin,rootIndex-1);
root.right = build(preorder,inorder,rootIndex+1,inend);
return root;
}
private int indexOfInorder(int[] inorder, int val, int inbegin, int inend) {
for (int j = inbegin; j <= inend ; j++) {
if(inorder[i] == val){
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] preorder,int[] inorder){
if(preorder.length == 0 || inorder.length == 0){
return null;
}
return build(preorder,inorder,0,inorder.length-1);
}
}