常见面试算法题(树专题三:DFS构造树和其他)

276 阅读2分钟

第一部分、构造树相关问题

1. 从前序与中序遍历序列构造二叉树

leetcode-cn.com/problems/co…

class Solution {
    //前序 : 中左右  中序: 左中右
    Map<Integer,Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for(int i = 0 ; i < inorder.length ; i++) map.put(inorder[i] , i);
        return dfs(preorder , 0 , preorder.length-1 , inorder , 0 , inorder.length-1);
    }

    TreeNode dfs(int[] preorder , int ps , int pe , int[] inorder , int is , int ie){
        if(ps > pe || is > ie) return null;
        TreeNode root = new TreeNode(preorder[ps]);
        int index = map.get(preorder[ps]); //中序遍历中root的位置
        int l = index - is;
        root.left = dfs(preorder , ps + 1, ps + l , inorder , is , index-1);
        root.right = dfs(preorder , ps +1 +l , pe , inorder , index + 1 , ie);
        return root;

    }
}

2. 从中序与后序遍历序列构造二叉树

leetcode-cn.com/problems/co…

class Solution {
    //左中右     左右中
    Map<Integer, Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        for(int i = 0 ; i < inorder.length ; i++) map.put(inorder[i] , i);
        return dfs(inorder , 0 , inorder.length-1 , postorder , 0 , postorder.length-1);
    }

    TreeNode dfs(int[] inorder , int is , int ie , int[] postorder , int ps , int pe){
        if(is > ie || ps > pe) return null;
        TreeNode root = new TreeNode(postorder[pe]);
        int index = map.get(postorder[pe]);
        int l = index - is;
        root.left = dfs(inorder , is , index-1 , postorder , ps , ps + l-1);
        root.right = dfs(inorder , index+1 ,ie ,postorder , ps + l , pe-1);
        return root;
    }
}

3. 从前序与后序遍历序列构造二叉树

leetcode-cn.com/problems/co…

class Solution {
    //前:中左右  后:左右中
    Map<Integer,Integer> map = new HashMap<>();
    public TreeNode constructFromPrePost(int[] pre, int[] post) {
        for(int i = 0 ; i < post.length ; i ++) map.put(post[i] , i);
        return dfs(pre , 0 , pre.length-1 , post , 0 , post.length-1);
    }

    TreeNode dfs(int[] pre , int ps , int pe , int[] post , int pl , int pr){
        if(ps > pe || pl > pr) return null;
        TreeNode root = new TreeNode(pre[ps]);
        if(ps == pe) return root; //也是递归终止条件
        int index = map.get(pre[ps+1]); //左子树的根节点 -- 关键
        int l = index - pl;
        root.left = dfs(pre , ps+1 , ps+1+l , post , pl , pl + l );
        root.right = dfs(pre , ps+l+2 , pe , post , pl+l+1 , pr-1);
        return root;
    }
}

第二部分、树的其他问题

4. 二叉搜索树与双向链表的转换

leetcode-cn.com/problems/er…

class Solution {
    Node pre = null;
    Node head = null;
    public Node treeToDoublyList(Node root) {
        if(root == null) return root;
        dfs(root);
        pre.right = head;
        head.left = pre;
        return head;
    }

    void dfs(Node root){
        if(root == null) return;
        dfs(root.left);

        root.left = pre;
        if(pre == null) head = root;
        else pre.right = root;

        pre = root;
        dfs(root.right);
    }
}

5.二叉树转换成先序单链表

leetcode-cn.com/problems/fl…

class Solution {
    public void flatten(TreeNode root) {
        if(root == null) return;
        TreeNode oldRight = root.right;
        root.right = root.left;
        root.left = null;

        //找到原先左子树的最右节点
        TreeNode tem = root;
        while(tem.right != null) tem = tem.right;

        //将原来的左子树接到最右节点的右子树上
        tem.right = oldRight;

        flatten(root.left); //左子树已经置为空了,所以可以省略
        flatten(root.right);

    }
}

6.二叉树的所有路径

leetcode-cn.com/problems/bi…

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> binaryTreePaths(TreeNode root) {
        if(root == null) return res;
        StringBuilder sb = new StringBuilder();
        dfs(root , sb);
        return res;
    }

    void dfs(TreeNode root , StringBuilder sb){
        if(root == null) return;
        int n = sb.length(); //先记录初始位置
        sb.append(root.val);
        sb.append("->");
        if(root.left == null && root.right == null){
            sb.deleteCharAt(sb.length()-1);
            sb.deleteCharAt(sb.length()-1);
            res.add(new String(sb));
        }
        dfs(root.left , sb);
        dfs(root.right , sb);
        sb.delete(n , sb.length());

    }
}

7.合并二叉树

leetcode-cn.com/problems/me…

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null) return root2;
        if(root2 == null) return root1;
        TreeNode root = new TreeNode(root1.val + root2.val);
        root.left = mergeTrees(root1.left , root2.left);
        root.right = mergeTrees(root1.right , root2.right);
        return root;

    }
}

8.二叉树剪枝

leetcode-cn.com/problems/bi…

class Solution {
    public TreeNode pruneTree(TreeNode root) {
        if(root == null) return root;
        if(isZero(root)) return null;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode curNode = queue.poll();
            if(isZero(curNode.left)) curNode.left = null;
            if(isZero(curNode.right)) curNode.right = null;
            if(curNode.left != null) queue.add(curNode.left);
            if(curNode.right != null) queue.add(curNode.right);
        }
        return root;
    }


    //判断以root为跟节点的子树是否含有1
    boolean isZero(TreeNode root){
        if(root == null) return true;
        return isZero(root.left) && isZero(root.right) && root.val == 0;
    }
}

9. 具有所有最深节点的最小子树

leetcode-cn.com/problems/sm…

class Solution {
    public TreeNode subtreeWithAllDeepest(TreeNode root) {
        //具有所有最深节点的最小子树左右子树的高度必定相等
        if(root == null) return root;
        int l = maxDepth(root.left);
        int r = maxDepth(root.right);
        if(l < r) return subtreeWithAllDeepest(root.right);
        else if(l > r) return subtreeWithAllDeepest(root.left);
        return root;
    }

    int maxDepth(TreeNode root){
        if(root == null) return 0;
        return Math.max(maxDepth(root.left) , maxDepth(root.right)) + 1;
    }
}

10. 找树左下角的值

leetcode-cn.com/problems/fi…

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            root = queue.poll();
            //先加右边的值,再加左边的值,确保最后一个出来的是最左边的值
            if(root.right != null) queue.add(root.right);
            if(root.left != null) queue.add(root.left);
        }
        return root.val;
    }
}