剑指offer——二叉树集合(LeetCode)

本文深入解析了二叉树及其衍生结构的多种经典面试题,包括重建二叉树、判断子结构、镜像翻转、对称检测、层次遍历、后序遍历验证、路径和查找、转换为双向链表、寻找第k大节点、深度计算、平衡判断、最近公共祖先等,提供了详细的算法思路与代码实现。

面试题07.重建二叉树

题目链接
前序遍历找到当前子树根节点
中序遍历将左右子树继续下分

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder.length==0||preorder==null){
            return null;
        }
        Map<Integer,Integer> indexMap=new HashMap<Integer,Integer>();
        int length=preorder.length;
        for(int i=0;i<length;i++){
            indexMap.put(inorder[i],i);
        }
        return buildTree(preorder,0,length-1,inorder,0,length-1,indexMap);
    }

    public TreeNode buildTree(int[] preorder,int preStart,int preEnd,int[] inorder,int orderStart,int orderEnd,Map<Integer,Integer> indexMap){
        if(preStart>preEnd){
            return null;
        }
        //先通过前序遍历找到当前子树根节点
        int rootVal=preorder[preStart];
        TreeNode root=new TreeNode(rootVal);
        if(preStart==preEnd){
            return root;
        }else{
            //中序遍历继续划分子树
            int rootIndex=indexMap.get(rootVal);
            int leftNode=rootIndex-orderStart,rightNode=orderEnd-rootIndex;
            TreeNode left=buildTree(preorder,preStart+1,preStart+leftNode,inorder,orderStart,rootIndex-1,indexMap);
            TreeNode right=buildTree(preorder,preStart+leftNode+1,preEnd,inorder,rootIndex+1,orderEnd,indexMap);
            root.left=left;
            root.right=right;
            return root;
        }
    }
}

面试题26. 树的子结构

题目链接
给定A树和B树,判断B树是否是A树子树。

  1. B树是A树子树:
    B树=A树,A树.左子树=B树,A树.右子树=B树
  2. 判断两棵树相等:
    树节点值相等;两棵树左右子树相等。

对这两个情况以此判断。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        if(A==null || B==null){
            return false;
        }
        return isSameTree(A,B) || isSubStructure(A.left,B) || isSubStructure(A.right,B);
    }
    public boolean isSameTree(TreeNode A,TreeNode B){
        if(B==null) return true;
        if(A==null) return false;
        return A.val==B.val && isSameTree(A.left,B.left) &&isSameTree(A.right,B.right);
    }
}

面试题27. 二叉树的镜像

题目链接
解法一:递归
先将当前树节点的左右子树交换,再继续向下递归交换左右子树各自的子树。直到处理完,root==null时返回。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root==null) return null;
        TreeNode tmp=root.left;
        root.left=root.right;
        root.right=tmp;
        mirrorTree(root.left);
        mirrorTree(root.right);
        return root;
    }
}

解法二:迭代(栈)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root==null) return null;
        Stack<TreeNode> st=new Stack<TreeNode>();
        st.push(root);
        while(!st.empty()){
            TreeNode node=st.pop();
            TreeNode tmp=node.left;
            node.left=node.right;
            node.right=tmp;
            if(node.left!=null) st.push(node.left);
            if(node.right!=null) st.push(node.right);
        }
        return root;
    }
}

面试题28. 对称的二叉树

题目链接

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root==null){
            return true;
        }
        return isSame(root.left,root.right);
    }

    private boolean isSame(TreeNode left,TreeNode right){
        if(left==null && right==null){
            return true;
        }
        if(left==null || right==null){
            return false;
        }
        return (left.val==right.val) && isSame(left.left,right.right) && isSame(left.right,right.left);
    }
}

从上到下打印二叉树

面试题32 - I.

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。题目
在这里插入图片描述
要依次得到左右节点,使用LinkedList,实现deque功能。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] levelOrder(TreeNode root) {
        List<Integer> res=new ArrayList<Integer>();
        if(root==null){
            return new int[res.size()];
        }
        LinkedList<TreeNode> st=new LinkedList<>();
        st.add(root);
        while(st.size()>0){
            TreeNode tmp=st.removeFirst();
            res.add(tmp.val);
            if(tmp.left!=null){
                st.add(tmp.left);
            }
            if(tmp.right!=null){
                st.add(tmp.right);
            }
        }
        int[] ans=new int[res.size()];
        for(int i=0;i<res.size();i++){
            ans[i]=res.get(i);
        }
        return ans;
    }
}
面试题32 - II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。题目
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res=new ArrayList<>();
        if(root==null){
            return res;
        }
        LinkedList<TreeNode> list=new LinkedList<TreeNode>();
        list.add(root);
        while(list.size()>0){
            List<Integer> tmp=new ArrayList<Integer>();
            int length=list.size();
            for(int i=0;i<length;i++){
                TreeNode now=list.removeFirst();
                tmp.add(now.val);
                if(now.left!=null) list.add(now.left);
                if(now.right!=null) list.add(now.right);
            }
            res.add(tmp);
        }
        return res;
    }
}
面试题32 - III

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
添加链接描述
在这里插入图片描述

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res=new ArrayList<>();
        if(root==null){
            return res;
        }
        LinkedList<TreeNode> list=new LinkedList<TreeNode>();
        list.add(root);
        int index=0;
        while(list.size()>0){
            List<Integer> tmp=new ArrayList<Integer>();
            int length=list.size();
            for(int i=0;i<length;i++){
                TreeNode now=list.removeFirst();
                tmp.add(now.val);
                if(now.left!=null) list.add(now.left);
                if(now.right!=null) list.add(now.right);
            }
            if((++index)%2==0){
                Collections.reverse(tmp);
            }
            res.add(tmp);
        }
        return res;
    }
}

面试题33. 二叉搜索树的后序遍历序列

题目链接
本题关键:利用二叉搜索树的左子树<根节点<右子树的特征
方法一:递归。
按照二叉搜索树的特点,在子树中迭代判断。

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        int length=postorder.length;
        return check(postorder,0,length-1);
    }

    private boolean check(int[]postorder,int l,int r){
        if(l>=r){
            return true;
        }
        int root=postorder[r];
        int p=0;
        while(postorder[p]<root) p++;
        int m=p;
        while(postorder[p]>root) p++;
        return p==r && check(postorder,l,m-1) && check(postorder,m,r-1);
    }

}

比较起来递归的方法要快

方法二:栈

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        int length=postorder.length;
        Stack<Integer> st=new Stack<>();
        int root=Integer.MAX_VALUE;
        for(int i=length-1;i>=0;i--){
            if(root<postorder[i]) return false;
            while(!st.empty() && postorder[i]<st.peek()){
                root=st.pop();
            }
            st.add(postorder[i]);
        }
        return true;
    }
}

面试题34. 二叉树中和为某一值的路径

题目
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> tmp=new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        getSum(root,sum);
        return res;
    }

    void getSum(TreeNode root,int sum){
        if(root==null){
            return;
        }
        tmp.add(root.val);
        sum-=root.val;
        if(sum==0 && root.left==null && root.right==null){
            res.add(new ArrayList(tmp)); // 这里注意不能直接res.add(tmp);
        }
        getSum(root.left,sum);
        getSum(root.right,sum);
        tmp.remove(tmp.size()-1);
    }
}

面试题36. 二叉搜索树与双向链表

题目链接
题目看起来比较复杂,实际是将二叉搜索树转换为一个 “排序的循环双向链表” ,其中包含三个要素:

  • 排序链表: 节点从小到大排序 --> 使用中序遍历, “从小到大”访问树的节点;

  • 双向链表

  • 循环链表

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val,Node _left,Node _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
    Node pre,head;
    public Node treeToDoublyList(Node root) {
        if(root==null){
            return null;
        }
        dfs(root);
        pre.right=head;head.left=pre;
        return head;
    }

    void dfs(Node cur){
        if(cur==null){
            return;
        }
        dfs(cur.left);
        if(pre!=null) pre.right=cur;
        else head=cur;
        cur.left=pre;
        pre=cur;
        dfs(cur.right);
    }
}

面试题54. 二叉搜索树的第k大节点

题目

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int ans=0,count=0;

    public int kthLargest(TreeNode root, int k) {
        getKthLargest(root,k);
        return ans;
    }

    private void getKthLargest(TreeNode root,int k){
        if(root.right!=null) getKthLargest(root.right,k);
        count++;
        if(count==k){
            ans=root.val;
            return;
        }
        if(root.left!=null) getKthLargest(root.left,k);
    }
}

面试题55 - I. 二叉树的深度

题目

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int maxDepth=0;
    public int maxDepth(TreeNode root) {
        getDepth(root,1);
        return maxDepth;
    }

    void getDepth(TreeNode root,int h){
        if(root==null){
            return;
        }
        if(root.left==null && root.right==null){
            if(h>maxDepth) maxDepth=h;
        }
        getDepth(root.left,h+1);
        getDepth(root.right,h+1);
    }
}

面试题55 - II. 平衡二叉树

题目
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

做的时候卡壳是因为忽然想不到如果递归求树的高度,那么怎么返回布尔值判断是否差距为1,其实直接返回高度/ -1 就可以了啊

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        return getHeight(root)==-1?false:true;
    }

    private int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        int right=getHeight(root.right)+1;
        if(right==-1) return -1;
        int left=getHeight(root.left)+1;
        if(left==-1) return -1;
        if(Math.abs(right-left)<=1){
            return Math.max(left,right);
        }else{
            return -1;
        }
    }
}

最近公共祖先

面试题68 - I. 二叉搜索树的最近公共祖先

题目
二叉树的解法也可以解这里的二叉搜索树。这里给出针对二叉搜索树的解法。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 //这里关键是注意二叉搜索树的特性
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        int pVal=p.val;
        int qVal=q.val;
        TreeNode node=root;

        while(node!=null){
            int parentVal=node.val;
            if(pVal<parentVal&&qVal<parentVal){
                node=node.left;
            }
            else if(pVal>parentVal&&qVal>parentVal){
                node=node.right;
            }
            else{
                return node;
            }
        }
        return null;
    }
}
面试题68 - II. 二叉树的最近公共祖先

题目

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){
            return null;
        }
        if(root==p||root==q){
            return root;
        }
        TreeNode left=lowestCommonAncestor(root.left,p,q);
        TreeNode right=lowestCommonAncestor(root.right,p,q);
        if(left!=null && right!=null){
            return root;
        }
        if(left!=null){
            return left;
        }
        if(right!=null){
            return right;
        }
        return null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值