刷题整理 - 递归和树

https://leetcode-cn.com/problems/climbing-stairs/

22. 括号生成

怎么检验合法性:

左括号随时可以加,只要不超过个数

右括号的个数必须小于等于左括号个数

这是递归,不是回溯。递归只需要每次往下走一层,回溯还需要剪枝

class Solution {
    List<String> result = new ArrayList<>();
    public List<String> generateParenthesis(int n) {
        generate(n, 0, 0, "");
        return result;
    }
    public void generate(int n, int left, int right, String s) {
        if (left == n && right == n) { // 递归结束条件左右括号数都等于n
            result.add(s);
            return;
        }
        if (left < n) { // 如果左括号数小于n,加左括号
            generate(n, left + 1, right, s + '(');
        }
        if (right < left) { // 如果右括号数小于左括号数,加右括号
            generate(n, left, right + 1, s + ')');
        }
    }
}

590. N 叉树的后序遍历

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> postorder(Node root) {
        // 结束条件
        if (root == null) {
            return new ArrayList<>();
        }
        // 需要做的操作
        for (Node n : root.children) { // 遍历子节点
            postorder(n);
        }
        res.add(root.val); // 遍历完子节点后,把root加入res
        return res;
    }
}

226. 翻转二叉树

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

98. 验证二叉搜索树

class Solution {
    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        Stack<TreeNode> stack = new Stack<>();
        long pre = Long.MIN_VALUE;
        while (!stack.isEmpty() || root != null) {
            if (root != null) {
                stack.push(root);
                root = root.left;
            } else {
                root = stack.pop();
                if (pre >= root.val) {
                    return false;
                }
                pre = root.val;
                root = root.right;
            }
        }
        return true;
    }
}

104. 二叉树的最大深度

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

111. 二叉树的最小深度

class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = minDepth(root.left);
        int right = minDepth(root.right);
        if (left == 0 && right == 0) { // root是叶子节点
            return 1;
        } else if (left == 0) { // 如果root左为空
            return right + 1;
        } else if (right == 0) { // 如果root右为空
            return left + 1;
        } else { // 如果root左右都不为空
            return left > right ? right + 1 : left + 1;
        }
    }
}

297. 二叉树的序列化与反序列化

  1. 序列化:通过层序遍历,序列化成字符串
  2. 反序列化:先把字符串分割成数组,然后把数组放进队列中,通过递归构造二叉树。
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) {
            return "#_";
        }
        String res = "";
        
        res += root.val;
        res += "_";
        res += serialize(root.left);
        res += serialize(root.right);
        return res;
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        String[] strings = data.split("_");
        Deque<String> queue = new LinkedList<>();
        for (int i = 0; i < strings.length; i++) {
            queue.add(strings[i]);
        }
        return recur(queue);
    }
    public TreeNode recur(Deque<String> queue) {
        if (queue.isEmpty()) {
            return null;
        }
        String s = queue.poll();
        if (s.equals("#")) {
            return null;
        }
        TreeNode root = new TreeNode(Integer.valueOf(s));
        root.left = recur(queue);
        root.right = recur(queue);
        return root;
    }
}

236. 二叉树的最近公共祖先

有三种情况

  1. p、q在root两端
  2. p = root,且 q 在 root 的左或右子树中
  3. q = root,且 p 在 root 的左或右子树中
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return root;
        }
        
        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;
        } else if (left != null) {
            return left;
        } else {
            return right;
        }
    }
}

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

前序:【根,[左子树的前序遍历结果],[右子树的前序遍历结果]】

中序:【[左子树的中序遍历结果],根,[右子树的中序遍历结果]】

class Solution {
    // 把中序遍历的值和下标放进map中,方便定位
    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); // 把中序遍历的值和下标放进map中,方便定位
        }
        return buildTreeHelp(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
    }
    // 参数:前序遍历和中序遍历的范围
    public TreeNode buildTreeHelp(int[] preorder, int[] inorder, int preLeft, int preRight, int inLeft, int inRight) {
        if (preLeft > preRight) {
            return null;
        }
        // 前序遍历第一个节点就是根节点
        int rootVal = preorder[preLeft];
        // 新建根节点
        TreeNode root = new TreeNode(rootVal);
        // 在中序遍历中定位根节点
        int inRoot = map.get(rootVal);
        // 左子树的数量
        int leftSize = inRoot - inLeft;
        TreeNode left = buildTreeHelp(preorder, inorder, preLeft + 1, preLeft + leftSize, inLeft, inRoot - 1);
        TreeNode right = buildTreeHelp(preorder, inorder, preLeft + leftSize + 1, preRight, inRoot + 1, inRight);
        root.left = left;
        root.right = right;
        return root; 
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值