数据结构java版之二叉树(部分offer面试题篇)

 不准看我金钱豹!看下面!!!

目录

一、二叉树的基本操作

1.获取树中节点的个数

2.获取叶子节点的个数

3.子问题思路-求叶子结点个数

4.获取第K层节点的个数

5.获取二叉树的高度

6.检测值为value的元素是否存在

7.判断一棵树是不是完全二叉树

二、二叉树相关oj题

1. 检查两颗树是否相同

2. 另一颗树的子树

3. 二叉树最大深度

4. 判断一颗二叉树是否是平衡二叉树

5. 对称二叉树

6. 二叉树的构建及遍历

7. 二叉树的分层遍历

8. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先

9. 二叉树搜索树转换成排序双向链表

10. 根据一棵树的前序遍历与中序遍历构造二叉树

11. 根据一棵树的中序遍历与后序遍历构造二叉树

12. 二叉树创建字符串

13. 二叉树前序非递归遍历实现

14. 二叉树中序非递归遍历实现


一、二叉树的基本操作

1.获取树中节点的个数

两种思考方式:

①遍历思路:

   定义一个计数器count,遍历二叉树,如果有结点就count++;(此处的遍历方式,可以是在上章博客里写到的前中后序遍历中的任何一种)

代码如下:!!!注意count需要定义在该函数外部,否则当递归时其count值会回到初始化er

 int count=0;
    //以遍历的思路写
    int size1(BTNode root){
        if(root==null) {
            return 0;
        }else{
            count++;
             size1(root.left);
             size1(root.right);
        }
        return count;
    }

②子问题思路:

 代码如下:

    //以子问题思路写
    int size(BTNode root){
        if(root==null){
            return 0;
        }
       return  size(root.left)+size(root.right)+1;
    }

2.获取叶子节点的个数

两种思考方式:

①遍历实现:

代码:

//以遍历的方式访问
    int count1=0;
    int getLeafNodeCount(BTNode root){
       // int count1=0;
        if(root==null){
            return 0;
        }else if(root.left==null && root.right==null){
            count1++;
        }
        getLeafNodeCount(root.left);
        getLeafNodeCount(root.right);
        return count1;
    }

②子问题思路:

代码如下:

int getLeafNodeCount(BTNode root){
        if(root==null){
            return 0;
        }else if(root.left==null && root.right==null){
            return 1;
        }
        return getLeafNodeCount(root.left)+getLeafNodeCount(root.right);
    }
}

3.子问题思路-求叶子结点个数

     该题在2中第二个思路中已经求得

4.获取第K层节点的个数

 解题思路:

代码如下:

//求第K层结点的个数
 public int getKLevelNodeCount(int k){
    return getKLevelNodeCount(root, k);
    }
     // 获取第K层结点的个数
    private int getKLevelNodeCount(BTNode root,int k){
          if(root==null || k<=0){
             return 0;
          }
          if(k==1){
              return 1;
          }
          return getKLevelNodeCount(root.left, k-1)+getKLevelNodeCount(root.right, k-1);

    }

5.获取二叉树的高度

思路分析:

代码如下:

 // 获取二叉树的高度(时间复杂度为O(n))
    int getHeight(BTNode root){
        if(root==null){
            return 0;
        }
       int leftHeight=getHeight(root.left);
        int rightHeight=getHeight(root.right);
//此处用的是三目运算符求取两者中的较大值
        return leftHeight>rightHeight?leftHeight+1:rightHeight+1;
    }

6.检测值为value的元素是否存在

解题思路:

代码如下 :

// 检测值为value的元素是否存在
    boolean find(BTNode root, int val) {
        if (root == null) {
            return false;
        } else if (root.val == val) {
            return true;
        }
        if (find(root.left, val) || find(root.right, val)) {
            return true;
        }
        return false;
    }

7.判断一棵树是不是完全二叉树

解题思路:

代码如下:

  boolean isCompleteTree(BTNode root){
        if(root == null) return true;
        Queue<BTNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            BTNode cur = queue.poll();
            if(cur != null) {
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else {
                break;
            }
        }
//第二个while循环实质上就是在cur=null的基础上来判断实现的,若是整个为空即null 则true;反之为false
        while (!queue.isEmpty()) {
            BTNode top = queue.peek();
            if(top != null) {
                return false;
            }
            queue.poll();
        }
        return true;
    }

1. 检查两颗树是否相同

100. 相同的树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/same-tree/

解题思路:

   要判断两棵树是否相同: 

   ①数的结构相同

   ②相应位置的结点对应的数值相同

代码如下:

 public boolean isSameTree(TreeNode p, TreeNode q ){
        if(p == null && q != null || p != null && q == null) {
            return false;
        }
        if(p == null && q == null) {
            return true;
        }
        if(p.val != q.val) {
            return false;
        }
        //p != null && q!= null && p.val == q.val
        return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
    }

2. 另一颗树的子树

572. 另一棵树的子树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/subtree-of-another-tree/

代码如下:

 public boolean isSubtree(TreeNode root, TreeNode subRoot) {
  if(root == null || subRoot == null) {
             return false;
         }
        //根节点和subroot是不是两颗相同的树
        if(isSameTree(root,subRoot)) {
            return true;
        }
        //subRoot是不是root的左子树
        if(isSubtree(root.left,subRoot)) {
            return true;
        }
        if(isSubtree(root.right,subRoot)) {
            return true;
        }
        return false;
}
}

3. 二叉树最大深度

104. 二叉树的最大深度 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/

 同二叉树基本操作的5题,请参考此篇博客上方

4. 判断一颗二叉树是否是平衡二叉树

110. 平衡二叉树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/balanced-binary-tree/submissions/

解题思路: 

class Solution {
   public int height (TreeNode root) {
        if(root == null) {return 0;}
        int leftHeight = height(root.left);
        int rightHeight = height(root.right);
        return (leftHeight > rightHeight) ?
                (leftHeight+1) :(rightHeight+1);
    }

    /**
     时间复杂度:O(N^2)
     */
    public boolean isBalanced(TreeNode root) {
        if(root == null) return true;
        int left = height(root.left);
        int right = height(root.right);
        return Math.abs(left-right) <= 1 && isBalanced(root.left) && isBalanced(root.right);
    }
}

5. 对称二叉树

101. 对称二叉树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/symmetric-tree/解题思路:

代码如下:

class Solution {
     public boolean isSymmetric(TreeNode root) {
        if(root == null) return true;
        return isSymmetricChild(root.left,root.right);
    }
   public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
       //第一种情况
       if(leftTree == null && rightTree == null) return true;
       //第二种情况
        if((leftTree == null && rightTree != null)||(leftTree != null && rightTree == null))               return false;
        //第三种情况
        if(leftTree.val != rightTree.val) return false;
        return isSymmetricChild(leftTree.left,rightTree.right) &&
                isSymmetricChild(leftTree.right,rightTree.left);
    }

6. 二叉树的构建及遍历牛客网链接icon-default.png?t=M0H8http:///www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef?tpId=60&&tqId=29483&rp=1&ru=/activity/oj&qru=/ta/tsing-kaoyan/question-ranking

7. 二叉树的分层遍历

102. 二叉树的层序遍历 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/binary-tree-level-order-traversal/

解题思路:

借助一个队列和一个临时变量cur来打印分层遍历

①讨论根是否为空的情况

②当队列不为空时,出队列中的队尾元素到cur中,并通过cur.val进行打印

③循环讨论子左右子树的情况,所以要用while进行循环

两类代码:

①普通代码:

  //打印层序遍历二叉树
  public void levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
//①判断树是否为空的情况
        if(root == null) return;
        queue.offer(root);
//②判断队列是否为空
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            System.out.print(cur.val+" ");
            if(cur.left != null) {
                queue.offer(cur.left);
            }
            if(cur.right != null) {
                queue.offer(cur.right);
            }
        }
    }

②OJ上解题的代码:

解题思路: 

代码如下:

//层序遍历访问打印元素
List<List<Integer>> ret = new ArrayList<>();
        if(root == null) return ret;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
//当前的结点个数size
            int size = queue.size();
            List<Integer> list = new ArrayList<>();
            while (size != 0) {
                TreeNode cur = queue.poll();
//将同层结点放在一个list中
                list.add(cur.val); 
                if(cur.left != null) {
                    queue.offer(cur.left);
                }
                if(cur.right != null) {
                    queue.offer(cur.right);
                }
                size--;//1 0
            }
//将所有一层link的结点放在同一个list中
            ret.add(list);
        }
//最后返回整个所需的ret
        return ret;
}

8. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/

解题思路:

思路①:由二叉搜索树的思想来设计二叉树的方法

若是二叉搜索树

详细思路:

1.root==p || root==q(p,q为结点)
此时的最近公共祖先是root
2.可能均在根的左边或者右边
①p.val<root.val && q.val<root.val(p,q均在root的左子树中)
最近公共祖先在左子树中


②p.val>root.val && q.val>root.val(p,q均在root的右子树中)
最近公共祖先在右子树中


3.最近的公共祖先就是root
①p.val>root.val && q.val<root.val(p在左子树中,q在右子树中)
②p.val<root.val && q.val>root.val(p在右子树中,q在左子树中)


 代码如下:

//二叉树的最近公共祖先
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){
            return null;
        }if(root==p||root==q){
            return root;
        }
        TreeNode l=lowestCommonAncestor(root.left,p,q);
        TreeNode r=lowestCommonAncestor(root.right,p,q);
       if(l!=null && r!=null){
    return root;
}else if(l!=null){
    return l;
}else{
    return r;
}
        }
    }

 思路②

由孩子双亲表示法来求取 

代码如下:

class Solution {
    //root:
    public boolean getPath(TreeNode root,TreeNode node,Stack<TreeNode>stack){
if(root==null || node==null){
return false;
}stack.push(root);
if(root==node){
    return true;
}
boolean flg=getPath(root.left,node,stack);
if(flg==true){
    return true;
}
 flg=getPath(root.right,node,stack);
 if(flg==true){
     return true;
 }
stack.pop();
return false;
    }
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){
            return null;
        }
        Stack<TreeNode> stack1=new Stack<>();
        getPath(root,p,stack1);
        Stack<TreeNode> stack2=new Stack<>();
        getPath(root,q,stack2);
        int size1=stack1.size();
        int size2=stack2.size();
        if(size1>size2){
            int size=size1-size2;
            while(size!=0){
            stack1.pop();
            size--;
            }
            while(!stack1.isEmpty() && !stack2.isEmpty()){
                //用等号判断地址
                if(stack1.peek()==stack2.peek()){
                    return stack1.pop();
                }else{
                    stack1.pop();
                    stack2.pop();
                }
            }
            }else{
                 int size=size2-size1;
            while(size!=0){
            stack2.pop();
            size--;
            }
            while(!stack1.isEmpty() && !stack2.isEmpty()){
                //用等号判断地址
                if(stack1.peek()==stack2.peek()){
                    return stack1.pop();
                }else{
                    stack1.pop();
                    stack2.pop();
                }
            }
            }
            return null;
        }
    }

9. 二叉树搜索树转换成排序双向链表

牛客网链接https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&&tqId=11179&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking解题思路:

前面已介绍过二叉搜索树的特点(因此已知当二叉搜索树中序遍历时是有序的)

①中序遍历这棵二叉树

②双向链表

 代码如下:

public class Solution {
    //先写出一个中序遍历
    TreeNode prev=null;
    public void inOrder(TreeNode pCur){
        if(pCur==null)return ;
        inOrder(pCur.left);
        pCur.left=prev;
        if(prev!=null){
              prev.right=pCur;
        }
      prev=pCur;
          inOrder(pCur.right);
    }
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree==null){
            return null;
        }
        inOrder(pRootOfTree);
        TreeNode head=pRootOfTree;
        while(head.left!=null){
            head=head.left;
        }
        return head;
    }
}

10. 根据一棵树的前序遍历与中序遍历构造二叉树

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

解题思路:

①找到根结点

②通过中序遍历找到左右子树

③分别创建左右子树

代码如下:

class Solution {
//将preIndex设置为全局变量用来保证在递归的过程中当子树根结点返回到总根后的空指针异常
    public int preIndex=0;
    public TreeNode createTreeByPandI(int[]preorder,int[]inorder,int inbegin,int inend){
        if(inbegin>inend){
            //左树或者右树为空
            return null;
        }
        TreeNode root=new TreeNode(preorder[preIndex]);
        int rootIndex=findIndexOfI(inorder,inbegin,inend,preorder[preIndex]);
            if(rootIndex==-1){
                return null;
            }
            preIndex++;
            root.left=createTreeByPandI(preorder,inorder,inbegin,rootIndex-1);
            root.right=createTreeByPandI(preorder,inorder,rootIndex+1,inend);
            return root;
        }
    private int findIndexOfI(int[]inorder,int inbegin,int inend,int key){
        for(int i=inbegin;i<=inend;i++){
            if(inorder[i]==key){
                return i;
            }
        }
return -1;
    }
    public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder==null||inorder==null){
    return null;
}return createTreeByPandI(preorder,inorder,0,inorder.length-1);
    }
}

11. 根据一棵树的中序遍历与后序遍历构造二叉树

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/解题思路:

与上个题的不同点:

①postIndex是在最右边(即根结点由后序遍历的话,先后往前进行遍历)

②先访问右树后访问左树

代码如下:

class Solution {
 public int postIndex=0;
    public TreeNode createTreeByPandI(int[]inorder,int[]postorder,int inbegin,int inend){
        if(inbegin>inend){
            //左树或者右树为空
            return null;
        }
        TreeNode root=new TreeNode(postorder[postIndex]);
        int rootIndex=findIndexOfI(inorder,inbegin,inend,postorder[postIndex]);
            if(rootIndex==-1){
                return null;
            }
            postIndex--;
            //分别创建右子树和左子树
            root.right=createTreeByPandI(inorder,postorder,rootIndex+1,inend);
            root.left=createTreeByPandI(inorder,postorder,inbegin,rootIndex-1);
            return root;
        }
    private int findIndexOfI(int[]inorder,int inbegin,int inend,int key){
        for(int i=inbegin;i<=inend;i++){
            if(inorder[i]==key){
                return i;
            }
        }
return -1;
    }
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        postIndex=postorder.length-1;
if(postorder==null||inorder==null){
    return null;
}return createTreeByPandI(inorder,postorder,0,inorder.length-1);
    }
}

 12. 二叉树创建字符串

606. 根据二叉树创建字符串 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/construct-string-from-binary-tree/
解题思路:

 代码如下:

class Solution {
  public void treeToString(TreeNode t,StringBuilder sb) {
        if(t == null) return;
        sb.append(t.val);
        if(t.left != null) {
            sb.append("(");
            treeToString(t.left,sb);
            sb.append(")");
        }else {
            //t.left == null
            if(t.right == null) {
                return;
            }else{
                sb.append("()");
            }
        }

        if(t.right == null) {
            return;
        }else{
            sb.append("(");
            treeToString(t.right,sb);
            sb.append(")");
        }
    }
    public String tree2str(TreeNode root) {
        if(root == null) return null;
        StringBuilder sb = new StringBuilder();
        treeToString(root,sb);
        return sb.toString();
    }
}

13. 二叉树前序非递归遍历实现

144. 二叉树的前序遍历 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/binary-tree-preorder-traversal/submissions/

解题思路:

代码如下:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer>ret=new ArrayList<>();
        Stack<TreeNode>stack=new Stack<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                ret.add(cur.val);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            System.out.print(top.val+" ");
            cur = top.right;
        }
        return ret;
    }

14. 二叉树中序非递归遍历实现

94. 二叉树的中序遍历 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/binary-tree-inorder-traversal/

解题思路:同13的前序非递归的遍历实现

代码如下:

class Solution {
 public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> ret= new ArrayList<>();
            Stack<TreeNode> stack = new Stack<>();
            TreeNode cur = root;
            while (cur != null || !stack.isEmpty()) {
                if (cur != null) {
                    stack.push(cur);
                    cur = cur.left;
                } else {
                    cur = stack.pop();
                    ret.add(cur.val);
                    cur = cur.right;
                }
            }
            return ret;
        }
    }

猜你喜欢

转载自blog.csdn.net/weixin_58850105/article/details/122564501