算法-二叉树算法总结

1 二叉树的遍历

1.1 前序遍历

  • 递归
// 144. 二叉树的前序遍历
// 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        preOrder(root,res);
        return res;
    }

    private void preOrder(TreeNode root,List<Integer> res) {
        if (root == null) return;
        res.add(root.val);
        preOrder(root.left,res);
        preOrder(root.right,res);
    }
}
  • 迭代
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode tmpNode = stack.pop();
            res.add(tmpNode.val);
            if (tmpNode.right != null) stack.push(tmpNode.right);
            if (tmpNode.left != null) stack.push(tmpNode.left);
        }
        return res;
    }
}

1.2 中序遍历

  • 递归
// 94. 二叉树的中序遍历
// 给定一个二叉树的根节点 root ,返回它的 中序 遍历。
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        inOrder(root,res);
        return res;
    }

    private void inOrder(TreeNode root,List<Integer> res) {
        if (root == null) return;
        inOrder(root.left,res);
        res.add(root.val);
        inOrder(root.right,res);
    }
}
  • 迭代
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        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();
                res.add(cur.val);
                cur = cur.right;
            }
        }
        return res;
    }
}

1.3 后序遍历

  • 递归
// 145. 二叉树的后序遍历
// 给定一个二叉树,返回它的 后序 遍历。
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        postOrder(root,res);
        return res;
    }

    private void postOrder(TreeNode root,List<Integer> res) {
        if (root == null) return;
        postOrder(root.left,res);
        postOrder(root.right,res);
        res.add(root.val);
    }
}
  • 迭代
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode tmpNode = stack.pop();
            res.add(tmpNode.val);
            if (tmpNode.left != null) stack.push(tmpNode.left);
            if (tmpNode.right != null) stack.push(tmpNode.right);
        }
        Collections.reverse(res);
        return res;
    }
}

1.4 层序遍历

// 102. 二叉树的层序遍历
// 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
class Solution {

    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int len = queue.size();
            List<Integer> tmpList = new ArrayList<>();
            for (int i = 0; i < len; i++) {
                TreeNode tmpNode = queue.poll();
                tmpList.add(tmpNode.val);
                if (tmpNode.left != null) queue.offer(tmpNode.left);
                if (tmpNode.right != null) queue.offer(tmpNode.right);
            }
            res.add(tmpList);
        }
        return res;
    }
}

2 二叉树的属性

思路:

  • 如果需要搜索整颗二叉树且不用处理递归返回值,递归函数就不要返回值。113
  • 如果需要搜索整颗二叉树且需要处理递归返回值,递归函数就需要返回值。 236
  • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。112
// DFS 后序遍历

// 101. 对称二叉树
// 给定一个二叉树,检查它是否是镜像对称的。
class Solution {
    public boolean isSymmetric(TreeNode root) {
        return compare(root.left,root.right);
    }

    private boolean compare (TreeNode left, TreeNode right) {
        if (left == null && right != null) return false;
        if (left != null && right == null) return false;
        if (left == null && right == null) return true;
        if (left.val != right.val) return false;

        boolean outFlag = compare(left.left,right.right);
        boolean inFlag = compare(left.right,right.left);
        return outFlag && inFlag;
    }
}
// DFS 后序遍历

// 104. 二叉树的最大深度
// 给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
class Solution {
    public int maxDepth(TreeNode root) {
        return getDepth(root);
    }

    private int getDepth(TreeNode root) {
        if (root == null) return 0;
        int leftDepth = getDepth(root.left);
        int rightDepth = getDepth(root.right);
        return 1 + Math.max(leftDepth,rightDepth);
    }
}
// DFS 后序遍历

// 559. N 叉树的最大深度
// 给定一个 N 叉树,找到其最大深度。最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
class Solution {
    public int maxDepth(Node root) {
        if (root == null) return 0;
        int maxDepth = 0;
        for (int i = 0 ; i < root.children.size(); i++) {
            int deep = maxDepth(root.children.get(i));
            maxDepth = Math.max(maxDepth,deep);
        }
        return 1 + maxDepth;
    }
}
// DFS 后序遍历

// 111. 二叉树的最小深度
// 给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
class Solution {
    public int minDepth(TreeNode root) {
        return getDepth(root);
    }

    private int getDepth(TreeNode root) {
        if (root == null) return 0;
        int leftDepth = getDepth(root.left);
        int rightDepth = getDepth(root.right);
        if (root.left == null && root.right != null) {
            return 1 + rightDepth;
        } else if (root.left != null && root.right == null) {
            return 1 + leftDepth;
        } else {
            return 1 + Math.min(leftDepth,rightDepth);
        }
    }
}
// DFS 后序遍历

// 222. 完全二叉树的节点个数
// 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) return 0;
        int leftNum = countNodes(root.left);
        int rightNum = countNodes(root.right);
        return 1 + leftNum + rightNum;
    }
}
// DFS 后序遍历

// 110. 平衡二叉树
// 给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
class Solution {
    public boolean isBalanced(TreeNode root) {
        return getHeight(root) == -1 ? false : true;
    }

    private int getHeight(TreeNode root) {
        if (root == null) return 0;
        int leftHeight = getHeight(root.left);
        if (leftHeight == -1) {
            return -1;
        }
        int rightHeight = getHeight(root.right);
        if (rightHeight == -1) {
            return -1;
        }
        return Math.abs(leftHeight - rightHeight) > 1 ? -1 : 1 + Math.max(leftHeight,rightHeight);
    }
}
// DFS 前序遍历

// 257. 二叉树的所有路径
// 给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<>();
        if (root == null) return res;
        List<Integer> paths = new ArrayList<>();
        traversal(root,paths,res);
        return res;
    }

    private void traversal(TreeNode root,List<Integer> paths,List<String> res) {
        paths.add(root.val);
        if (root.left == null && root.right == null) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < paths.size() - 1; i++) {
                sb.append(paths.get(i) + "->");
            }
            sb.append(paths.get(paths.size() - 1));
            res.add(sb.toString());
            return;
        }
        if (root.left != null) {
            traversal(root.left,paths,res);
            paths.remove(paths.size() - 1);
        }
        if (root.right != null) {
            traversal(root.right,paths,res);
            paths.remove(paths.size() - 1);
        }
    }
}
// DFS 后序遍历

// 404. 左叶子之和
// 计算给定二叉树的所有左叶子之和。
class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if (root == null) return 0;
        int leftValue = sumOfLeftLeaves(root.left);
        int rightValue = sumOfLeftLeaves(root.right);
        int midValue = 0;
        if (root.left != null && root.left.left == null && root.left.right == null) {
            midValue = root.left.val;
        }
        return leftValue + rightValue + midValue;
    }
}
// DFS 前序遍历

// 513. 找树左下角的值
// 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。假设二叉树中至少有一个节点。
class Solution {
    private int maxDeep;
    private int maxVal;
    public int findBottomLeftValue(TreeNode root) {
        maxVal = root.val;
        maxDeep = 0;
        travesal(root,0);
        return maxVal;
    }

    private void travesal(TreeNode root,int tmpDeep) {
        if (root == null) return;
        if (root.left == null && root.right == null) {
            if (tmpDeep > maxDeep) {
                maxDeep = tmpDeep;
                maxVal = root.val;
            }
        }
        travesal(root.left,tmpDeep + 1); //隐式回溯
        travesal(root.right,tmpDeep + 1);
    }
}
// DFS 前序遍历(中节点没有逻辑)

// 112. 路径总和
// 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) return false;
        return traversal(root,targetSum - root.val);   
    }

    private boolean traversal(TreeNode root, int tmpSum) {
        if (root.left == null && root.right == null && tmpSum == 0) return true;
        if (root.left == null && root.right == null) return false;

        if (root.left != null) {
            if (traversal(root.left,tmpSum - root.left.val)) return true;
        } 
        if (root.right != null) {
            if (traversal(root.right,tmpSum - root.right.val)) return true;
        }
        return false;
    }
}
// DFS 前序遍历

// 113. 路径总和 II
// 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
class Solution {
    private List<List<Integer>> res = new ArrayList<>();
    private List<Integer> path = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        if (root == null) return res;
        path.add(root.val);
        traversal(root,targetSum - root.val);
        return res;
    }

    private void traversal(TreeNode root, int tmpNum) {
        if (root.left == null && root.right == null && tmpNum == 0) {
            res.add(new ArrayList<>(path));
            return;
        }
        if (root.left == null && root.right == null) return;
        if (root.left != null) {
            path.add(root.left.val);
            tmpNum -= root.left.val;
            traversal(root.left,tmpNum);
            tmpNum += root.left.val;
            path.remove(path.size() - 1);
        }
        if (root.right != null) {
            path.add(root.right.val);
            tmpNum -= root.right.val;
            traversal(root.right,tmpNum);
            tmpNum += root.right.val;
            path.remove(path.size() - 1);
        }
    }
}

3 二叉树的修改与构造

// DFS 前序遍历

// 226. 翻转二叉树
// 翻转一棵二叉树。
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) return root;
        swap(root);
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }

    private void swap(TreeNode root) {
        TreeNode tmpNode = root.left;
        root.left = root.right;
        root.right = tmpNode;
    }
}
// 106. 从中序与后序遍历序列构造二叉树
// 根据一棵树的中序遍历与后序遍历构造二叉树。
class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        return buildTree(inorder,0,inorder.length,postorder,0,postorder.length);
    }

    private TreeNode buildTree(int[] inorder,int inLeft,int inRight,int[] postorder,int postLeft,int postRight) {
        if (inRight - inLeft < 1) return null;
        int rootVal = postorder[postRight - 1];
        TreeNode root = new TreeNode(rootVal);
        int rootIndex = 0;
        for (int i = inLeft; i < inRight; i++) {
            if (inorder[i] == rootVal) {
                rootIndex = i;
                break;
            }
        }
      // 根据rootIndex划分左右子树
        root.left = buildTree(inorder,inLeft,rootIndex,postorder,postLeft,postLeft + (rootIndex - inLeft));
        root.right = buildTree(inorder,rootIndex + 1,inRight,postorder,postLeft + (rootIndex - inLeft),postRight - 1);
        return root;
    }
}
// DFS 前序遍历

// 105. 从前序与中序遍历序列构造二叉树
// 给定一棵树的前序遍历 preorder 与中序遍历  inorder。请构造二叉树并返回其根节点。
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTree(preorder,0,preorder.length,inorder,0,inorder.length);
    }

    private TreeNode buildTree(int[] preorder,int preLeft,int preRight,int[] inorder,int inLeft,int inRight) {
        if (inRight - inLeft < 1) return null;
        int rootVal = preorder[preLeft];
        TreeNode root = new TreeNode(rootVal);
        int rootIndex = 0;
        for (int i = inLeft; i < inRight; i++) {
            if (inorder[i] == rootVal) {
                rootIndex = i;
                break;
            }
        }
        root.left = buildTree(preorder,preLeft + 1,preLeft + 1 + (rootIndex - inLeft),inorder,inLeft,rootIndex);
        root.right = buildTree(preorder,preLeft + 1 + (rootIndex - inLeft),preRight,inorder,rootIndex + 1,inRight);
        return root;
    }
}
// DFS 前序遍历

// 654. 最大二叉树
// 给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:二叉树的根是数组 nums 中的最大元素。左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。返回有给定数组 nums 构建的 最大二叉树 。
class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return constructMaximumBinaryTree(nums,0,nums.length);
    }

    private TreeNode constructMaximumBinaryTree(int[] nums,int preLeft,int preRight) {
        if (preRight - preLeft < 1) return null;
        // 初始赋值
        int maxValue = nums[preLeft];
        int maxIndex = preLeft;
        for (int i = preLeft + 1; i < preRight; i++) {
            if (nums[i] > maxValue) {
                maxValue = nums[i];
                maxIndex = i;
            }
        }
        TreeNode root = new TreeNode(maxValue);
        root.left = constructMaximumBinaryTree(nums,preLeft,maxIndex);
        root.right = constructMaximumBinaryTree(nums,maxIndex + 1,preRight);
        return root;
    }
}
// DFS 前序遍历

// 617. 合并二叉树
// 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
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;
    }
}

4 二叉搜索树

思路:

  1. 二叉搜索树是一个有序树:
  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉搜索树
  1. 中序遍历下,输出的二叉搜索树节点的数值是有序序列。
// DFS 搜索遍历 找到结果直接return

// 700. 二叉搜索树中的搜索
// 给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if (root == null || root.val == val) return root;
        if (root.val > val) return searchBST(root.left,val);
        if (root.val < val) return searchBST(root.right,val);
        return null;
    }
}
// DFS 中序遍历 找到结果直接return

// 98. 验证二叉搜索树
// 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。有效 二叉搜索树定义如下:节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。
class Solution {
    private long pre = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if (root == null) return true;
        if (!isValidBST(root.left)) return false;
        if (root.val <= pre) return false;
        pre = root.val;
        return isValidBST(root.right);
    }
}
// DFS 中序遍历

// 530. 二叉搜索树的最小绝对差
// 给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。差值是一个正数,其数值等于两值之差的绝对值。
class Solution {
    private TreeNode pre;
    private int diff = Integer.MAX_VALUE;
    public int getMinimumDifference(TreeNode root) {
        if (root == null) return 0;
        traversal(root);
        return diff;
    }

    private void traversal(TreeNode root) {
        if (root == null) return;
        traversal(root.left);
        if (pre != null) {
            diff = Math.min(diff,root.val - pre.val);
        }
        pre = root;
        traversal(root.right);
    }
}
// DFS 中序遍历

// 501. 二叉搜索树中的众数
// 给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
class Solution {
    private List<Integer> resList = new ArrayList<>();
    private TreeNode pre;
    private int maxCount = 0;
    private int count = 0;
    public int[] findMode(TreeNode root) {
        traversal(root);
        int[] res = new int[resList.size()];
        for (int i = 0; i < res.length; i++) {
            res[i] = resList.get(i);
        }
        return res;
    }

    private void traversal(TreeNode root) {
        if (root == null) return;
        traversal(root.left);
        if (pre == null || root.val != pre.val) {
            count = 1;
        } else {
            count++;
        }
        if (count > maxCount) {
            maxCount = count;
            resList.clear();
            resList.add(root.val);
        } else if (count == maxCount) {
            resList.add(root.val);
        }
        pre = root;
        traversal(root.right);
    }
}
// DFS 中序遍历变种

// 538. 把二叉搜索树转换为累加树
// 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
class Solution {
    private int sum = 0;

    public TreeNode convertBST(TreeNode root) {
        traversal(root);
        return root;
    }

    private void traversal(TreeNode root) {
        if (root == null) return;
        traversal(root.right);
        sum += root.val;
        root.val = sum;
        traversal(root.left);
    }
}

5 二叉树的公共祖先问题

思路 :

  1. 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从低向上的遍历方式。
  2. 在回溯的过程中,必然要遍历整颗二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
// DFS 后序遍历

// 本题函数有返回值,是因为回溯的过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。递归函数有返回值就是要遍历某一条边,但有返回值也要看如何处理返回值。如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树呢?
// 搜索一条边的写法:
// if (递归函数(root->left)) return ;
// if (递归函数(root->right)) return ;
// 搜索整个树写法:
// left = 递归函数(root->left);
// right = 递归函数(root->right);
// left与right的逻辑处理;
// 在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。

// 236. 二叉树的最近公共祖先
// 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return traversal(root,p,q);
    }

    private TreeNode traversal(TreeNode root,TreeNode p,TreeNode q) {
        if (root == p || root == q || root == null) return root;
        TreeNode leftNode = traversal(root.left,p,q);
        TreeNode rightNode = traversal(root.right,p,q);
        if (leftNode != null && rightNode != null) { 
            return root;
        } else if (leftNode == null && rightNode != null) {
            return rightNode;
        } else if (leftNode != null && rightNode == null) {
            return leftNode;
        } else {
            return null;
        }
    }
}
// DFS 前序遍历(节点无处理逻辑)

// 和二叉树:公共祖先问题不同,普通二叉树求最近公共祖先需要使用回溯,从底向上来查找,二叉搜索树就不用了,因为搜索树有序(相当于自带方向),那么只要从上向下遍历就可以了。

// 235. 二叉搜索树的最近公共祖先
// 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return traversal(root,p,q);
    }

    private TreeNode traversal(TreeNode root,TreeNode p,TreeNode q) {
        if (root == null) return null;
        if (root.val > p.val && root.val > q.val) {
            TreeNode leftNode = traversal(root.left,p,q);
            if (leftNode != null) return leftNode;
        }
        if (root.val < p.val && root.val < q.val) {
            TreeNode rightNode = traversal(root.right,p,q);
            if (rightNode != null) return rightNode;
        }
        return root;
    }
}

6 二叉搜索树的修改与构造

// DFS 搜索遍历

// 有返回值的话,可以利用返回值完成新加入的节点与其父节点的赋值操作

// 701. 二叉搜索树中的插入操作
// 给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) {
            TreeNode node = new TreeNode(val);
            return node;
        }
        if (root.val > val) root.left = insertIntoBST(root.left,val);
        if (root.val < val) root.right = insertIntoBST(root.right,val);
        return root;
    }
}
// DFS 搜索遍历

// 有以下五种情况:
// 第一种情况:
        // 没找到删除的节点,遍历到空节点直接返回了
// 找到删除的节点:
        // 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
        // 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
        // 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
        // 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。


// 450. 删除二叉搜索树中的节点
// 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) return null;
        if (root.val == key) {
            if (root.left == null && root.right == null) {
                return null;
            } else if (root.left != null && root.right == null) {
                return root.left;
            } else if (root.left == null && root.right != null) {
                return root.right;
            } else {
                TreeNode cur = root.right;
                while (cur.left != null) {
                    cur = cur.left;
                }
                cur.left = root.left;
                return root.right;
            }
        }
        if (root.val > key) root.left = deleteNode(root.left,key);
        if (root.val < key) root.right = deleteNode(root.right,key);
        return root;
    }
}
// DFS 搜索遍历

// 因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。但是有返回值,更方便,可以通过递归函数的返回值来移除节点。

// 669. 修剪二叉搜索树
// 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树不应该改变保留在树中的元素的相对结构(即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。
class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) return null;
        if (root.val < low) {
            TreeNode rightNode = trimBST(root.right,low,high);
            return rightNode;
        }
        if (root.val > high) {
            TreeNode leftNode = trimBST(root.left,low,high);
            return leftNode;
        }
        root.left = trimBST(root.left,low,high);
        root.right = trimBST(root.right,low,high);
        return root;
    }
}
// DFS 前序遍历

// 108. 将有序数组转换为二叉搜索树
// 给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return traversal(nums,0,nums.length - 1); // [left,right]
    }

    private TreeNode traversal(int[] nums,int left,int right) {
        if (left > right) return null;
        int mid = left + ((right - left) >> 1);
        TreeNode root = new TreeNode(nums[mid]);
        root.left = traversal(nums,left,mid - 1);
        root.right = traversal(nums,mid + 1,right);
        return root;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城老湿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值