算法:二叉树题目总结

二叉树的递归法和统一迭代法

题目1:144. 二叉树的前序遍历
思路:中左右
1)递归法

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result =new ArrayList<>();
        Stack<TreeNode> stack=new Stack<>();
        if(root==null){
            return result;
        }
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node= stack.pop();
            result.add(node.val);
            //中
            if (node.right != null){
                  //右
                stack.add(node.right);
            }
            if(node.left != null){
            //左
            stack.add(node.left);
            }
        }
        return result;
    }
}

2)统一迭代法 前序:中左右 入栈的话就是右左中 辅助数据结构:栈

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> st = new Stack<>();
        if (root != null) st.push(root);
        while (!st.empty()) {
            TreeNode node = st.peek();
            if (node != null) {
                st.pop(); // 先弹把中点弹出去,后面跟右中左再加回来
                if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)
                if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)
                st.push(node);                          // 添加中节点
                st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
                
            } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
                st.pop();           // 将空节点弹出
                node = st.peek();    // 重新取出栈中元素
                st.pop();
                result.add(node.val); // 加入到结果集
            }
        }
        return result;
    }
}

题目2:94. 二叉树的中序遍历
思路:左中右
1)递归法

class Solution {

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result=new ArrayList<>();
        traveral(root,result);
        return result;
    }

    void traveral(TreeNode root,List<Integer> result){
        if(root==null){return;}
        traveral(root.left,result);
        result.add(root.val);
        traveral(root.right,result);
    }
}

2)统一迭代法 中序:左中右 入栈的话就是右中左 辅助数据结构:栈

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> st = new Stack<>();
        if (root != null) st.push(root);
        while (!st.empty()) {
            TreeNode node = st.peek();
            if (node != null) {
                st.pop(); // 先弹把中点弹出去,后面跟右中左再加回来
                if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)
                st.push(node);                          // 添加中节点
                st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
                if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)
            } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
                st.pop();           // 将空节点弹出
                node = st.peek();    // 重新取出栈中元素
                st.pop();
                result.add(node.val); // 加入到结果集
            }
        }
        return result;
    }
}

题目3:145. 二叉树的后序遍历
思路:左右中
1)递归法

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result=new ArrayList<Integer>();
        tranveral(root,result);
        return result;
    }

    void tranveral(TreeNode root,List<Integer> result){
        if(root==null){return;}
        tranveral(root.left,result);
        tranveral(root.right,result);
        result.add(root.val);
    }
}

2)统一迭代法 后序:左右中 入栈的话就是中右左 辅助数据结构:栈

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> st = new Stack<>();
        if (root != null) st.push(root);
        while (!st.empty()) {
            TreeNode node = st.peek();
            if (node != null) {
                st.pop(); // 先弹把中点弹出去,后面跟右中左再加回来
                st.push(node);                          // 添加中节点
                st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
                if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)
                if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)
            } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
                st.pop();           // 将空节点弹出
                node = st.peek();    // 重新取出栈中元素
                st.pop();
                result.add(node.val); // 加入到结果集
            }
        }
        return result;
    }
}

二叉树层序遍历

题目1:102. 二叉树的层序遍历
思路:用队列先进先出模拟层序遍历逻辑
1)递归法
2)迭代法

class Solution {

    public List<List<Integer>> resList = new ArrayList<List<Integer>>();

    public List<List<Integer>> levelOrder(TreeNode root) {
        levelOrderByQueue(root);
        return resList;
    }

     public void levelOrderByQueue(TreeNode node) {
        if (node == null) return;
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        que.offer(node);
        while(!que.isEmpty()){
            int size=que.size();
            List<Integer> itemList = new ArrayList<Integer>();
            while(size>0){
                TreeNode tmpNode=que.poll();
                itemList.add(tmpNode.val);
                if(tmpNode.left!=null){
                    que.offer(tmpNode.left);
                }
                if(tmpNode.right!=null){
                    que.offer(tmpNode.right);
                }
                size--;
            }
            resList.add(itemList);
        }
     }
}

题目2:107. 二叉树的层序遍历 II
思路:在层序遍历的基础上翻转数组

class Solution {

    List<List<Integer>> resList = new ArrayList<>();

    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        //层序遍历
        levelOrderByQueue(root);
        //反转数组
        List<List<Integer>> result = new ArrayList<>();
        for (int i = resList.size() - 1; i >= 0; i-- ) {
            result.add(resList.get(i));
        }
        return result;
    }

    
     public void levelOrderByQueue(TreeNode node) {
        if (node == null) return;
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        que.offer(node);
        while(!que.isEmpty()){
            int size=que.size();
            List<Integer> itemList = new ArrayList<Integer>();
            while(size>0){
                TreeNode tmpNode=que.poll();
                itemList.add(tmpNode.val);
                if(tmpNode.left!=null){
                    que.offer(tmpNode.left);
                }
                if(tmpNode.right!=null){
                    que.offer(tmpNode.right);
                }
                size--;
            }
            resList.add(itemList);
        }
     }
}

题目3:199. 二叉树的右视图
思路:在层序遍历的基础上,单层遍历取最有一个值就是最右边的值

class Solution {

    List<Integer> resList = new ArrayList<>();

    public List<Integer> rightSideView(TreeNode root) {
        //层序遍历
        levelOrderByQueue(root);
        return resList;
    }

     public void levelOrderByQueue(TreeNode node) {
        if (node == null) return;
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        que.offer(node);
        while(!que.isEmpty()){
            int size=que.size();
            TreeNode tmpNode=null;
            while(size>0){
                tmpNode=que.poll();
                if(tmpNode.left!=null){
                    que.offer(tmpNode.left);
                }
                if(tmpNode.right!=null){
                    que.offer(tmpNode.right);
                }
                size--;
            }
            resList.add(tmpNode.val);
        }
     }
}

题目4:637. 二叉树的层平均值
思路:在层序遍历的基础上,单层取平均值

class Solution {

    List<Double> resList = new ArrayList<>();

    public List<Double> averageOfLevels(TreeNode root) {
        levelOrderByQueue(root);
        return resList;
    }

    public void levelOrderByQueue(TreeNode node) {
        if (node == null) return;
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        que.offer(node);
        while(!que.isEmpty()){
            int size=que.size();
            double levelSum = 0.0;
            for (int i = 0; i < size; i++) {
                TreeNode tmpNode=que.poll();
                levelSum+=tmpNode.val;
                if(tmpNode.left!=null){
                    que.offer(tmpNode.left);
                }
                if(tmpNode.right!=null){
                    que.offer(tmpNode.right);
                }
            }
            resList.add(levelSum / size);
        }
     }
}

题目5:429. N 叉树的层序遍历
思路:在层序遍历的基础上,遍历children子节点

class Solution {

    List<List<Integer>> resList = new ArrayList<>();

    public List<List<Integer>> levelOrder(Node root) {
        levelOrderByQueue(root);
        return resList;
    }
     public void levelOrderByQueue(Node node) {
        if (node == null) return;
        Queue<Node> que = new LinkedList<Node>();
        que.offer(node);
        while(!que.isEmpty()){
            int size=que.size();
            List<Integer> itemList = new ArrayList<Integer>();
            for (int i = 0; i < size; i++) {
                Node tmpNode=que.poll();
                itemList.add(tmpNode.val);
                List<Node> children = tmpNode.children;
                if (children == null || children.size() == 0) {
                    continue;
                }
                for (Node child : children) {
                    if (child != null) {
                        que.offer(child);
                    }
                }
            }
            resList.add(itemList);
        }
     }
}

题目6:515. 在每个树行中找最大值
思路:在层序遍历的基础上,比较每一层的最大值

class Solution {

    List<Integer> resList = new ArrayList<>();

    public List<Integer> largestValues(TreeNode root) {
        levelOrderByQueue(root);
        return resList;
    }
    
    public void levelOrderByQueue(TreeNode node) {
        if (node == null) return;
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        que.offer(node);
        while(!que.isEmpty()){
            int size=que.size();
            int maxValue = Integer.MIN_VALUE;
            for(int i=0;i<size;i++){
                TreeNode tmpNode = que.poll();
                maxValue = Math.max(maxValue, tmpNode.val);
                if(tmpNode.left!=null){
                    que.offer(tmpNode.left);
                }
                if(tmpNode.right!=null){
                    que.offer(tmpNode.right);
                }
            }
            resList.add(maxValue);
        }
    }
}

题目7:116. 填充每个节点的下一个右侧节点指针
题目8:117. 填充每个节点的下一个右侧节点指针 II
思路:在层序遍历的基础上,做了很大改动,第一个节点单拿出来,因为最开始的next都是null值,所以每一层的null值不用额外设置,从第二个节点开始给next赋值

class Solution {

    public Node connect(Node root) {
        return levelOrderByQueue(root);
    }

    public Node levelOrderByQueue(Node node) {
        Queue<Node> tmpQueue = new LinkedList<Node>();
        if (node != null){
            tmpQueue.offer(node);
        }
       
        while(!tmpQueue.isEmpty()){
            int size=tmpQueue.size();
            Node cur = tmpQueue.poll();
            if (cur.left != null) tmpQueue.add(cur.left);
            if (cur.right != null) tmpQueue.add(cur.right);

            for(int i=1;i<size;i++){
            	Node next = tmpQueue.poll();
		        if (next.left != null) tmpQueue.add(next.left);
		        if (next.right != null) tmpQueue.add(next.right);
                cur.next = next;
                cur = next;
            }
        }
        return node;
    }
}

题目9:104. 二叉树的最大深度
思路:遍历完每一层后深度+1

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null)   return 0;
        Queue<TreeNode> que = new LinkedList<>();
        que.offer(root);
        int depth = 0;
        while (!que.isEmpty())
        {
            int len = que.size();
            while (len > 0)
            {
                TreeNode node = que.poll();
                if (node.left != null)  que.offer(node.left);
                if (node.right != null) que.offer(node.right);
                len--;
            }
            depth++;
        }
        return depth;
    }
}

题目10:111.二叉树的最小深度
思路:遍历每层时,发现左右孩子都为空 返回深度

class Solution {
    public int minDepth(TreeNode root){
        if (root == null) {
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int depth = 0;
        while (!queue.isEmpty()){
            int size = queue.size();
            depth++;
            TreeNode cur = null;
            for (int i = 0; i < size; i++) {
                cur = queue.poll();
                //如果当前节点的左右孩子都为空,直接返回最小深度
                if (cur.left == null && cur.right == null){
                    return depth;
                }
                if (cur.left != null) queue.offer(cur.left);
                if (cur.right != null) queue.offer(cur.right);
            }
        }
        return depth;
    }
}

二叉树递归法应用

重点:搞清楚每道题使用的前中后序遍历

二叉树前中后序递归法变种题型

题目1:226. 翻转二叉树

思路:前序和后序都行 中序会翻转后会导致第三层没翻转 可以想一下
1)递归法

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root==null){
            return root;
        }
        swap(root);
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }

    void swap(TreeNode root){
        TreeNode temp=root.left;
        root.left=root.right;
        root.right=temp;
    }
}

2)层序遍历 依靠队列

class Solution {

    public TreeNode invertTree(TreeNode root) {
        if (root == null) {return null;}
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
                TreeNode node = queue.poll();
                swap(node);//中
                if (node.right != null) queue.offer(node.right);//右
                if (node.left != null) queue.offer(node.left);//左
        }
        return root;
    }
    void swap(TreeNode root){
        TreeNode temp=root.left;
        root.left=root.right;
        root.right=temp;
    }
}

题目2:101. 对称二叉树

思路:只能用后序遍历 因为需要返回是否对称的结果给中间节点 对于左子树来说是左右中 对于右子树来说是右左中
1)递归法

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return compare(root.left, root.right);
    }
    boolean compare(TreeNode left,TreeNode right){
        if(left==null&&right==null) return true;
        if(left!=null&&right==null) return false;
        if(left==null&&right!=null) return false;
        if(left.val!=right.val) return false;
        boolean outside=compare(left.left,right.right);
        boolean inside=compare(left.right,right.left);
        return outside&&inside;
    }    
}

2)迭代法 层序遍历 需借助队列

class Solution {
    public boolean isSymmetric(TreeNode root) {
        Queue<TreeNode> que=new LinkedList<>();
        que.offer(root.left);
        que.offer(root.right);
        while(!que.isEmpty()){
            TreeNode leftNode = que.poll();
            TreeNode rightNode = que.poll();
            if(leftNode==null&&rightNode==null) continue;
            if(leftNode!=null&&rightNode==null) return false;
            if(leftNode==null&&rightNode!=null) return false;
            if(leftNode.val!=rightNode.val) return false;
            que.offer(leftNode.left);
            que.offer(rightNode.right);
            que.offer(leftNode.right);
            que.offer(rightNode.left);
        }
        return true;
    }
}

题目3:617. 合并二叉树

思路:前中后序递归法变种题型的解决办法
1)递归法

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

2)迭代法

class Solution {
    // 使用队列迭代
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if (root1 == null) return root2;
        if (root2 ==null) return root1;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root1);
        queue.offer(root2);
        while (!queue.isEmpty()) {
            TreeNode node1 = queue.poll();
            TreeNode node2 = queue.poll();
            // 此时两个节点一定不为空,val相加
            node1.val = node1.val + node2.val;
            // 如果两棵树左节点都不为空,加入队列
            if (node1.left != null && node2.left != null) {
                queue.offer(node1.left);
                queue.offer(node2.left);
            }
            // 如果两棵树右节点都不为空,加入队列
            if (node1.right != null && node2.right != null) {
                queue.offer(node1.right);
                queue.offer(node2.right);
            }
            // 若node1的左节点为空,直接赋值
            if (node1.left == null && node2.left != null) {
                node1.left = node2.left;
            }
            // 若node1的右节点为空,直接赋值
            if (node1.right == null && node2.right != null) {
                node1.right = node2.right;
            }
        }
        return root1;
    }
}

题目4:104. 二叉树的最大深度

思路:用前中后序都可以
1)递归法 返回最大深度+1是因为加上根节点

class Solution {
    public int maxDepth(TreeNode root) {
        // 如果root为空,直接返回0
        if (root == null) {
            return 0;
        }
        int left= maxDepth(root.left);
        int right=maxDepth(root.right);
        return Math.max(left,right)+1;

    }
}

2)迭代法 层序遍历借助队列

class Solution {
    public int maxDepth(TreeNode root) {
       if(root==null) return 0;
       Queue<TreeNode> que=new LinkedList<>();
       que.offer(root);
       int depth = 0;
       while(!que.isEmpty()){
           int size=que.size();
           depth++;
           for(int i=0;i<size;i++){
              TreeNode node= que.poll();
              if(node.left!=null) que.offer(node.left);
              if(node.right!=null) que.offer(node.right);
           }
       }
        return depth;
    }
}

题目5:111. 二叉树的最小深度

思路:这题有误区,最小深度是从根节点到最近叶子节点的最短路径上的节点数量 需要考虑左右子树是否为空的情况,如果左子树为空 最小深度=右子树最小深度+1 如果右子树为空 最小深度=左子树最小深度+1 如果左右子树都不为空 最小深度=左右子树深度最小值 + 1 。使用后序遍历方式
1)递归法

class Solution {
    public int minDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        int left=minDepth(root.left);
        int right=minDepth(root.right);
        //中
        if (root.left == null) {
            return right + 1;
        }
        if (root.right == null) {
            return left + 1;
        }
        // 左右结点都不为null
        return Math.min(left, right) + 1;
    }
}

2)迭代法 层序遍历借助队列

class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        Deque<TreeNode> que = new LinkedList<>();
        que.offer(root);
        int depth = 0;
        while (!que.isEmpty()) {
            int size = que.size();
            depth++;
            for (int i = 0; i < size; i++) {
                TreeNode node = que.poll();
                if (node.left == null && node.right == null) {
                    // 是叶子结点,直接返回depth,因为从上往下遍历,所以该值就是最小值
                    return depth;
                }
                if (node.left != null) {
                    que.offer(node.left);
                }
                if (node.right != null) {
                    que.offer(node.right);
                }
            }
        }
        return depth;
    }
}

题目6:222. 完全二叉树的节点个数

思路:
1)递归法

class Solution {
    public int countNodes(TreeNode root) {
        if(root==null) return 0;
        //统计左子树的数量
        int left= countNodes(root.left);
        //统计右子树的数量
        int right= countNodes(root.right);
        return left+right+1;
    }
}

2)迭代法 层序遍历借助队列

class Solution {
    public int countNodes(TreeNode root) {
        if(root==null) return 0;
        Queue<TreeNode> que=new LinkedList<>();
        que.offer(root);
        int length=1;
        while(!que.isEmpty()){
            int size=que.size();
            for(int i=0;i<size;i++){
               TreeNode node= que.poll();
               if(node.left!=null){
                   que.offer(node.left);
                   length++;
                } 
               if(node.right!=null){
                   que.offer(node.right);
                   length++;
               } 
            }
        }
       return length;
    }
}

二叉树前中后序递归法变种再变种题型

题目7:110. 平衡二叉树

思路:在求二叉树高度的基础上 如果高度差<=1并且左子树和右子树都为平衡二叉树
1)递归法

class Solution {
    public boolean isBalanced(TreeNode root) {
        //采用后序遍历
        if(root == null){
            return true;
        }
        int res = getHeight(root.left) > getHeight(root.right) ? getHeight(root.left) - getHeight(root.right) : getHeight(root.right) - getHeight(root.left);
        //容易出错:高度差小于1 并且左右子树都要是平衡二叉树
        if(res <= 1&&isBalanced(root.left)&&isBalanced(root.right)){
            return true;
        }else{
            return false;
        }
    }
    public int getHeight(TreeNode root){
        if(root == null){
            return 0;
        }else{
            int leftHeight = getHeight(root.left);
            int rightHeight = getHeight(root.right);
            return Math.max(leftHeight, rightHeight) + 1;
        }
    }
}

题目8:257. 二叉树的所有路径

思路:遍历二叉树节点的基础上通过SpringBuilder拼上每个节点
1)递归法

class Solution {
    List<String> res=new ArrayList<>();
    public List<String> binaryTreePaths(TreeNode root) {
        if(root==null) return res;
        getPaths(root,"");
        return res;
    }
    public void getPaths(TreeNode root,String path){
        if(root==null) return;
        StringBuilder sb=new StringBuilder(path);
        sb.append(root.val);
        //叶子节点要收集
        if(root.left==null&&root.right==null){
          res.add(sb.toString());
        }else{
            sb.append("->");
            getPaths(root.left,sb.toString());
            getPaths(root.right,sb.toString());
        }
    }
}

题目9:404. 左叶子之和

思路:
1)递归法

class Solution {
    int result = 0;
    public int sumOfLeftLeaves(TreeNode root) {
        if(root==null)return 0;
        if(root.left!=null&&root.left.left==null&&root.left.right==null){
            result+=root.left.val;
        }
        sumOfLeftLeaves(root.left);
        sumOfLeftLeaves(root.right);
        return result;
    }
}

二叉树回溯I题型

题目10:513. 找树左下角的值

思路:
1)递归法 最后一行就是找到深度最大的叶子结点,保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值

class Solution {
    private int maxDeep = -1;
    private int leftValue = 0;
    public int findBottomLeftValue(TreeNode root) {
        findLeftValue(root,0);
        return leftValue;
    }

    void findLeftValue(TreeNode root,int deep){
        if (root == null) return;
        if (root.left == null && root.right == null) {
            if (deep > maxDeep) {
                leftValue = root.val;
                maxDeep = deep;
            }
        }
        if (root.left != null){
            deep++;
            findLeftValue(root.left,deep);
            deep--;
        }
        if (root.right != null){
            deep++;
            findLeftValue(root.right,deep);
            deep--;
        }
    }
}
  1. 迭代法 层序遍历 借助队列 这道题层序遍历相对简单 只要找到最后一层的第一个元素即可,所以在层序遍历的基础上加了一个判断
    if(i==0){result=node.val;}
class Solution {
    int result=0;
    public int findBottomLeftValue(TreeNode root) {
        if(root==null){
            return 0;
        }
        returnBottomLeftValue(root);
        return result;
    }
    void returnBottomLeftValue(TreeNode root){
         if(root==null) return;
         Queue<TreeNode>que=new LinkedList<>();
         que.offer(root);
         while(!que.isEmpty()){
             int size=que.size();
             for(int i=0;i<size;i++){
                TreeNode node=  que.poll();
                if(i==0){result=node.val;}
                if(node.left!=null) que.offer(node.left);
                if(node.right!=null) que.offer(node.right);
             }
         }
    }
}

题目11:112. 路径总和

思路:
1)递归法 总和-遇到的每个节点值 如果遇到叶子节点总和等于0说明找到路径

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root==null) return false;
        targetSum-=root.val;
        if(root.left==null && root.right==null && targetSum==0) return true;
        if(root.left!=null){
           boolean leftResult= hasPathSum(root.left,targetSum);
           if(leftResult) return true;
        } 
        if(root.right!=null){
           boolean rightResult= hasPathSum(root.right,targetSum);
           if(rightResult) return true;
        }
        return false;
    }
}
  1. 迭代法 借助两个队列 一个存节点 一个存节点加起来的值(不能替换成累加值 会把整个的节点加起来,用队列这种可以保证左树加左树的和 右树加右树的和)
class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root == null) return false;
        Queue<TreeNode> q1 = new LinkedList<>();
        Queue<Integer> q2 = new LinkedList<>();
        q1.offer(root);
        q2.offer(root.val);
        while(!q1.isEmpty()) {
            int size = q1.size();
            for(int i = 0; i < size; i++) {
                TreeNode node = q1.poll();
                int sum = q2.poll();
                if(node.left == null && node.right == null && sum == targetSum) {
                    return true;
                }
                if(node.right != null){
                    q1.offer(node.right);
                    q2.offer(sum + node.right.val);
                }
                if(node.left != null) {
                    q1.offer(node.left);
                    q2.offer(sum + node.left.val);
                }
            }
        }
        return false;
    }
}

题目12:113. 路径总和 II

思路:
1)递归法 与路径总和提一样 就是多了个记录路径的变量
注意 result.add(new ArrayList(path)); 只添加path 最后结果是空

class Solution {
    List<List<Integer>> result=new ArrayList<>();
    List<Integer> path=new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        getPathSum(root,targetSum);
        return result;
    }
    void getPathSum(TreeNode root, int targetSum){
        if(root==null) return;
        targetSum-=root.val;
        path.add(root.val);
        if(root.left==null && root.right==null && targetSum==0){
        	//注意
            result.add(new ArrayList<Integer>(path));
        }
        if(root.left!=null){
            getPathSum(root.left,targetSum);
            //回溯
            path.remove(path.size() - 1);
        }
        if(root.right!=null){
            getPathSum(root.right,targetSum);
            //回溯
            path.remove(path.size() - 1);
        }
    }
}

二叉树构造I题型

题目13:106. 从中序与后序遍历序列构造二叉树

思路:
第一步:如果数组大小为零的话,说明是空节点了
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
1)递归法

class Solution {
    Map<Integer, Integer> map=new HashMap<>();
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        for (int i = 0; i < inorder.length; i++) { 
            // 用map保存中序序列的数值对应位置
            map.put(inorder[i], i);
        }
        return findNode(inorder,  0, inorder.length, postorder,0, postorder.length);
    }
    public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd) {
        // 参数里的范围都是前闭后开 防止越界
        if (inBegin >= inEnd || postBegin >= postEnd) {
            return null;
        }
        // 1.找到中间节点,后序数组最后一个元素
        // 2.找到中序切割点 rootIndex
        int rootIndex = map.get(postorder[postEnd - 1]);
        // 构造结点
        TreeNode root = new TreeNode(inorder[rootIndex]); 
        // 中序左子树个数
        int lenOfLeft = rootIndex - inBegin;
        //中序左数组, 后序左数组
        root.left = findNode(inorder, inBegin, rootIndex,postorder, postBegin, postBegin + lenOfLeft);
        //中序右数组, 后序右数组
        root.right = findNode(inorder, rootIndex + 1, inEnd,postorder, postBegin + lenOfLeft, postEnd - 1);
        return root;
    }
}

题目14:105. 从前序与中序遍历序列构造二叉树

思路:与上题思路一样
1)递归法

class Solution {
    Map<Integer, Integer> map=new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for (int i = 0; i < inorder.length; i++) { 
            // 用map保存中序序列的数值对应位置
            map.put(inorder[i], i);
        }
        return findNode(inorder,  0, inorder.length, preorder,0, preorder.length);
    }
    public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] preorder, int preBegin, int preEnd) {
        // 参数里的范围都是前闭后开 防止越界
        if (inBegin >= inEnd || preBegin >= preEnd) {
            return null;
        }
        // 1.找到中间节点,前序数组第一个元素
        // 2.找到中序切割点 rootIndex
        int rootIndex = map.get(preorder[preBegin]);
        // 构造结点
        TreeNode root = new TreeNode(inorder[rootIndex]); 
        // 中序左子树个数
        int lenOfLeft = rootIndex - inBegin;
        //中序左数组, 前序左数组
        root.left = findNode(inorder, inBegin, rootIndex,preorder, preBegin+1, preBegin + lenOfLeft+1);
        //中序右数组, 前序右数组
        root.right = findNode(inorder, rootIndex + 1, inEnd,preorder, preBegin + lenOfLeft+1, preEnd);
        return root;
    }
}

题目15:105. 从前序与中序遍历序列构造二叉树

思路:与上题思路一样
1)递归法

class Solution {
    Map<Integer, Integer> map=new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for (int i = 0; i < inorder.length; i++) { 
            // 用map保存中序序列的数值对应位置
            map.put(inorder[i], i);
        }
        return findNode(inorder,  0, inorder.length, preorder,0, preorder.length);
    }
    public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] preorder, int preBegin, int preEnd) {
        // 参数里的范围都是前闭后开 防止越界
        if (inBegin >= inEnd || preBegin >= preEnd) {
            return null;
        }
        // 1.找到中间节点,前序数组第一个元素
        // 2.找到中序切割点 rootIndex
        int rootIndex = map.get(preorder[preBegin]);
        // 构造结点
        TreeNode root = new TreeNode(inorder[rootIndex]); 
        // 中序左子树个数
        int lenOfLeft = rootIndex - inBegin;
        //中序左数组, 前序左数组
        root.left = findNode(inorder, inBegin, rootIndex,preorder, preBegin+1, preBegin + lenOfLeft+1);
        //中序右数组, 前序右数组
        root.right = findNode(inorder, rootIndex + 1, inEnd,preorder, preBegin + lenOfLeft+1, preEnd);
        return root;
    }
}

题目16:654. 最大二叉树

思路:和上题思路一样有些变种 找到每轮递归最大值的下标
1)递归法

lass Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
       return findNode(nums,0,nums.length);
    }
    public TreeNode findNode(int[] nums,Integer begin, Integer end) {
        // 没有元素了
        if (end - begin < 1) {
            return null;
        }
        Map<Integer, Integer> map=new HashMap<>();
        int max=-1;
        for (int i = begin; i < end; i++) {
            // 用map保存中序序列的数值对应位置
            map.put(nums[i], i);
            if(nums[i]>max){
                max=nums[i];
            }
        }
        TreeNode root = new TreeNode(max); 
        Integer index=map.get(max);
        root.left=findNode(nums,begin,index);
        root.right=findNode(nums,index+1,end);
        return root;
    }
}

二叉搜索树模版变种题型

题目17:700. 二叉搜索树中的搜索

思路:针对二叉搜索树的题目,一样要利用其特性
1)递归法 利用二叉搜索树的特性 大于往右子树搜索 小于往左子树搜索

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if (root == null || root.val == val) return root;
        TreeNode result=null;
        if(val<root.val){
            result=searchBST(root.left, val);
        }
        if(val>root.val){
            result=searchBST(root.right, val);
        }
        return result;
    }
}

2)迭代法 不需要队列(广度优先搜索)和栈(深度优先搜索)因为节点有序
普通二叉树需要有回溯过程 而二叉搜索树因为本身就是有序的所以不需要回溯过程

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        while (root != null && root.val != val) {
            root = root.val < val ? root.right : root.left;
        }
        return root;
    }
}

题目18:98. 验证二叉搜索树

思路:左子树所有节点小于中间节点,右子树所有节点大于中间节点,利用中序,整个节点是递增的
陷阱1:不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了,例如:[10,5,15,null,null,6,20],节点10大于左节点5,小于右节点15,但右子树里出现了一个6 这就不符合了!
1)递归法 中序遍历保证递增,始终与前一个节点进行比较就行

class Solution {
    TreeNode pre=null;
    public boolean isValidBST(TreeNode root) {
        if(root==null) return true;
        boolean left= isValidBST(root.left);
        if (pre != null && pre.val >= root.val) return false;
        // 记录前一个节点
        pre = root; 
        boolean right= isValidBST(root.right);
        return left&&right;
    }
}

题目19:530. 二叉搜索树的最小绝对差

思路:模版变种题 借助前一个节点
1)递归法

class Solution {
    TreeNode pre=null;
    int result = Integer.MAX_VALUE;
    public int getMinimumDifference(TreeNode root) {
        if(root==null) return 0;
        int left=getMinimumDifference(root.left);
        if(pre!=null){
            result = Math.min(result,root.val-pre.val);
        }
        pre=root;
        getMinimumDifference(root.right);
        return result;
    }
}

题目20:501. 二叉搜索树中的众数

思路:模版变种题 借助前一个节点
1)递归法 中序遍历

class Solution {
    ArrayList<Integer> resList=new ArrayList<>();
    int maxCount=0;
    int count=0;
    TreeNode pre=null;
    public int[] findMode(TreeNode root) {
        findMode1(root);
        int[] res = new int[resList.size()];
        for (int i = 0; i < resList.size(); i++) {
            res[i] = resList.get(i);
        }
        return res;
    }
    public void findMode1(TreeNode root) {
        if (root == null) {
            return;
        }
        findMode1(root.left);
        int rootValue = root.val;
        // 计数
        if (pre == null || rootValue != pre.val) {
            count = 1;
        } else {
            count++;
        }
        // 更新结果以及maxCount
        if (count > maxCount) {
            resList.clear();
            resList.add(rootValue);
            maxCount = count;
        } else if (count == maxCount) {
            resList.add(rootValue);
        }
        pre = root;
        findMode1(root.right);
    }
}

二叉搜索树回溯II题型

题目21:236. 二叉树的最近公共祖先

思路:
1)递归法 后序遍历

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || 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 null;
        }else if(left == null && right != null) {
            return right;
        }else if(left != null && right == null) {
            return left;
        }else {
            return root;
        }
    }
}

题目22:235. 二叉搜索树的最近公共祖先

思路:利用搜索二叉树有序特性,从上向下去递归遍历,第一次遇到 cur节点是数值在[p, q]区间中,那么cur就是 p和q的最近公共祖先。前中后序都可
1)递归法

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root.val > p.val && root.val > q.val){
            return lowestCommonAncestor(root.left, p, q);
        } 
        if (root.val < p.val && root.val < q.val){
            return lowestCommonAncestor(root.right, p, q);
        } 
        return root;
    }
}

二叉搜索树构造II题型

题目23:701. 二叉搜索树中的插入操作

思路:利用二叉搜索树有序特性 不用遍历整棵树
1)递归法

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) return new TreeNode(val);         
        if (root.val < val){
            root.right = insertIntoBST(root.right, val);
        }else if (root.val > val){
            root.left = insertIntoBST(root.left, val);
        }
        return root;
    }
}

题目24:450. 删除二叉搜索树中的节点

思路:
1.没找到删除的节点
遍历到空节点直接返回
2.找到删除的节点
1)左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
2) 删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
3)删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
4) 左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点
1)递归法

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        //1.没找到删除的节点,遍历到空节点直接返回
        if (root == null) return root;
        //2.找到删除的节点
        if (root.val == key) {
            if (root.left == null) {
                //1)删除节点的左孩子为空,右孩子不为空
                return root.right;
            } else if (root.right == null) {
                //2)删除节点的右孩子为空,左孩子不为空
                return root.left;
            } else {
                //3)左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点
                TreeNode cur = root.right;
                while (cur.left != null) {
                    cur = cur.left;
                }
                cur.left = root.left;
                root = root.right;
                return root;
            }
        }
        if (root.val > key) root.left = deleteNode(root.left, key);
        if (root.val < key) root.right = deleteNode(root.right, key);
        return root;
    }
}

题目25:669. 修剪二叉搜索树

思路:
1)递归法

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) {
            return null;
        }
        if (root.val < low) {
            return trimBST(root.right, low, high);
        }
        if (root.val > high) {
            return trimBST(root.left, low, high);
        }
        // root在[low,high]范围内
        root.left = trimBST(root.left, low, high);
        root.right = trimBST(root.right, low, high);
        return root;
    }
}

题目26:108. 将有序数组转换为二叉搜索树

思路:本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间。
1)递归法 与最大二叉树很像

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return sortedArrayToBST(nums, 0, nums.length);
    }
    public TreeNode sortedArrayToBST(int[] nums, int left, int right) {
        if (left >= right) {
            return null;
        }
        int mid = left + (right - left) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = sortedArrayToBST(nums, left, mid);
        root.right = sortedArrayToBST(nums, mid + 1, right);
        return root;
    }
}

题目27:538. 把二叉搜索树转换为累加树

思路:按右中左遍历累加

class Solution {
    int sum;
    public TreeNode convertBST(TreeNode root) {
        sum = 0;
        convertBST1(root);
        return root;
    }
    // 按右中左顺序遍历,累加即可
    public void convertBST1(TreeNode root) {
        if (root == null) {
            return;
        }
        convertBST1(root.right);
        sum += root.val;
        root.val = sum;
        convertBST1(root.left);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值