【代码随想录】刷题Day3【二叉树】

71 阅读1分钟

前言

二叉树种类

  1. 满二叉树:每一层的节点个数都达到了最大值
  2. 完全二叉树:相比满二叉树来说,完全二叉树的最后一层的节点是从左到右连续的
  3. 二叉搜索树:对于任意一棵树的根节点来说,左边都比根节点小,右边都比根节点大
  4. 平衡二叉搜索树:在二叉搜索树的基础上,它的左子树的高度与右子树的高度的差值 <= 1

存储方式

  1. 链式存储:左右指针
  2. 顺序存储:比如堆(假如根节点为0下标,那么左孩子为2i+1,右孩子2i+2)

遍历方式

  1. 深度优先:前中后序遍历
  2. 广度优先:层序遍历

递归三部曲

  1. 确定递归函数的参数和返回值
  2. 确定终止条件
  3. 确定单层递归的逻辑

144. 二叉树的前序遍历

题目

image.png

思路

  1. 递归
  2. 迭代:借助栈

代码

// 递归
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> list = new ArrayList<>();
    if(root == null) return list;

    list.add(root.val);
    List<Integer> ret = preorderTraversal(root.left);
    list.addAll(ret);

    ret = preorderTraversal(root.right);
    list.addAll(ret);

    return list;
}

// 迭代1
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.push(node.right);
        if(node.left != null) stack.push(node.left);
    }

    return result;
}

// 迭代2
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> list = new ArrayList<>();
    if(root == null) return list;

    Stack<TreeNode> stack = new Stack<>();
    TreeNode cur = root;

    while(cur != null || !stack.empty()) {
        while(cur != null) {
            stack.push(cur);
            list.add(cur.val);
            cur = cur.left;
        }
        // 弹出栈顶,走右边
        TreeNode top = stack.pop();
        cur = top.right;
    }
    return list;
}

145. 二叉树的后序遍历

题目

image.png

思路

  1. 递归
  2. 迭代:借助栈

代码

// 递归
public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> list = new ArrayList<>();
    if(root == null) return list;

    List<Integer> ret = postorderTraversal(root.left);
    list.addAll(ret);

    ret = postorderTraversal(root.right);
    list.addAll(ret);

    list.add(root.val);

    return list;
}

// 迭代1
public List<Integer> postorderTraversal(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.left != null) stack.push(node.left);
        if(node.right != null) stack.push(node.right);
    }
    Collections.reverse(result);
    return result;
}


// 迭代2
public List<Integer> postOrderTraversal(TreeNode3 root) {
    if(root == null) return list;

    List<Integer> list = new ArrayList<>();
    Stack<TreeNode3> stack = new Stack<>();

    TreeNode3 cur = root;
    TreeNode3 prev = null;  // 记录上一次打印的元素,防止死循环了
    while(cur != null || !stack.empty()) {
        while(cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
        // 不能弹出,继续走右边,右边为空才能弹出
        TreeNode3 top = stack.peek();
        if(top.right == null || prev == top) {
            stack.pop();
            list.add(top.val);
            prev = top;
        } else {
            cur = top.right;
        }
    }
    return list;
}

94. 二叉树的中序遍历

题目

image.png

思路

  1. 递归
  2. 迭代:借助栈

代码

// 递归
public void inorder(TreeNode root, List<Integer> ret) {
    if(root == null) {
        return;
    }

    inorder(root.left,ret);
    ret.add(root.val);
    inorder(root.right,ret);
}

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

// 迭代2
public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> list = new ArrayList<>();
    if(root == null) return list;

    Stack<TreeNode> stack = new Stack<>();
    TreeNode cur = root;

    while(cur != null || !stack.empty()) {
        while(cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
        // 弹出栈顶,走右边
        TreeNode top = stack.pop();
        list.add(top.val);
        cur = top.right;
    }
    return list;
}

注意点:

上述三种遍历操作中,对比:前序和后序的迭代1方法;前序和中序的迭代2方法

102. 二叉树的层序遍历

题目

image.png

思路

迭代:借助队列

代码

public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> ret = new ArrayList<>();
    if(root == null) return ret;

    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);

    while(!queue.isEmpty()) {
        int size = queue.size(); // 每一层的节点个数
        List<Integer> list = new ArrayList<>();
        while(size > 0) {
            TreeNode cur = queue.poll();
            list.add(cur.val);
            size--;
            if(cur.left != null) {
                queue.offer(cur.left);
            }

            if(cur.right != null) {
                queue.offer(cur.right);
            }
        }
        ret.add(list);
    }
    return ret;
}