LeetCode

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

112. 路径总和

给定一个二叉树和一个目标和,判断该树中是否存在根结点到叶子结点的路径,这条路径上所有结点值相加等于目标和。

  1. class Solution {
  2. public boolean hasPathSum(TreeNode root, int sum) {
  3. if (root == null) return false;
  4. if (root.left == null && root.right == null) {
  5. return sum - root.val == 0;
  6. }
  7. return hasPathSum(root.left, sum-root.val) || hasPathSum(root.right, sum-root.val);
  8. }
  9. }
  1. class Solution {
  2. public boolean hasPathSum(TreeNode root, int sum) {
  3. if (root == null) return false;
  4. Stack<TreeNode> st = new Stack<>();
  5. st.push(root);
  6. while (!st.empty()) {
  7. TreeNode t = st.pop();
  8. if (t.left == null && t.right == null) {
  9. if (t.val == sum) return true;
  10. }
  11. if (t.right != null) {
  12. t.right.val += t.val;
  13. st.push(t.right);
  14. }
  15. if (t.left != null) {
  16. t.left.val += t.val;
  17. st.push(t.left);
  18. }
  19. }
  20. return false;
  21. }
  22. }

113. 路径总和 II

给定一个二叉树和一个目标和,找到所有从根结点到叶子结点路径总和等于给定目标和的路径。**

  1. class Solution {
  2. public List<List<Integer>> pathSum(TreeNode root, int sum) {
  3. List<List<Integer>> res = new ArrayList<>();
  4. if (root == null) return res;
  5. helper(new ArrayList<>(), res, root, sum);
  6. return res;
  7. }
  8. private void helper(List<Integer> list, List<List<Integer>> res, TreeNode root, int sum) {
  9. list.add(root.val);
  10. if (root.left == null && root.right == null) {
  11. int cur = 0;
  12. for (int n : list) {
  13. cur += n;
  14. }
  15. if (cur == sum) {
  16. res.add(new ArrayList<>(list));
  17. return;
  18. }
  19. }
  20. if (root.left != null) {
  21. helper(list, res, root.left, sum);
  22. list.remove(list.size() - 1);
  23. }
  24. if (root.right != null) {
  25. helper(list, res, root.right, sum);
  26. list.remove(list.size() - 1);
  27. }
  28. }
  29. }

437. 路径总和 III

给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

思路:
递归关系,是包含 root 结点和不包含 root 结点两种情况之和。

  1. class Solution {
  2. public int pathSum(TreeNode root, int sum) {
  3. if (root == null) {
  4. return 0;
  5. }
  6. return dfs(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
  7. }
  8. private int dfs(TreeNode root, int sum) {
  9. int res = 0;
  10. if (root == null) {
  11. return 0;
  12. }
  13. if (root.val == sum) {
  14. res++;
  15. }
  16. res += dfs(root.left, sum - root.val);
  17. res += dfs(root.right, sum - root.val);
  18. return res;
  19. }
  20. }

129. 求根到叶子结点数字之和

给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子结点的路径都代表一个数字。
例如,从根到叶子结点路径 1->2->3 代表数字 123。
计算从根到叶子结点生成的所有数字之和。

思路:
常规解法,使用回溯法获取每一个 path,累加path的和。这样速度会比较慢。
更好的方法是,还是利用回溯的思想,不过我们将当前遍历到的结点值存到 cur 中。这样在遍历到下一个结点之前,我们已经有了累加值。

  1. class Solution {
  2. private int res = 0;
  3. public int sumNumbers(TreeNode root) {
  4. if (root == null) return 0;
  5. helper(root, 0);
  6. return res;
  7. }
  8. private void helper(TreeNode root, int cur) {
  9. cur = root.val + cur*10;
  10. if (root.left == null && root.right == null) {
  11. res += cur;
  12. return;
  13. }
  14. if (root.left != null) helper(root.left, cur);
  15. if (root.right != null) helper(root.right, cur);
  16. return;
  17. }
  18. }

257. 二叉树的所有路径

给定一个二叉树,返回所有从根结点到叶子结点的路径。

思路:
回溯法,注意递归和非递归两种写法。递归关系:左节点和右节点的所有路径可以构成根节点的路径。

class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> paths = new ArrayList<>();
        btPaths(root, paths, "");
        return paths;
    }

    public void btPaths(TreeNode root, List<String> paths, String s) {
        if(root == null) return;
        s = s + root.val;

        if(root.left == null && root.right == null) {
            paths.add(s);
        }

        s = s + "->";

        btPaths(root.left, paths, s);
        btPaths(root.right, paths, s);
    }
}
class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> list = new LinkedList<>();
        if(root == null) return list;
        Stack<TreeNode> stack = new Stack<>();
        HashMap<TreeNode, String> map = new HashMap<>();
        stack.push(root);
        map.put(root, "" + root.val);
        while(!stack.isEmpty()) {
            TreeNode cur = stack.pop();
            if(cur.left == null && cur.right == null) {
                list.add(map.get(cur));
            }
            if (cur.right != null) {
                stack.add(cur.right);
                map.put(cur.right, map.get(cur) + "->" + cur.right.val);
            }
            if (cur.left != null) {
                stack.add(cur.left);
                map.put(cur.left, map.get(cur) + "->" + cur.left.val);
            }
        }
        return list;
    }
}

199. 二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

思路:
使用深度优先遍历完成,注意顺序。使用层序遍历(todo)。

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        List<Integer> res = new ArrayList<>();
        if(root == null) return res;
        dfs(list, root, 0);
        for (List<Integer> l : list) {
            res.add(l.get(l.size()-1));
        }
        return res;
    }

    public void dfs(List<List<Integer>> res, TreeNode node, int level) {
        if(node == null) return;
        List<Integer> cur;
        if(level >= res.size()) {
            cur = new ArrayList<>();
            cur.add(node.val);
            res.add(cur);
        } else {
            cur = res.get(level);
            cur.add(node.val);
        }
        dfs(res, node.left, level+1);
        dfs(res, node.right, level+1);
    }
}

94. 二叉树的中序遍历

给定一个二叉树,返回它的 中序 遍历。

思路:
注意递归和非递归的写法。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        dfs(root, res);
        return res;
    }

    private void dfs(TreeNode root, List<Integer> res) {
        if (root.left != null) {
            dfs(root.left, res);
        }
        res.add(root.val);
        if (root.right != null) {
            dfs(root.right, res);
        }
    }
}
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            res.add(cur.val);
            cur = cur.right;
        }
        return res;
    }
}

练习:

144. 二叉树的前序遍历

使用非递归方法(todo)

145. 二叉树的后序遍历

使用非递归方法(todo)

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

958. 二叉树的完全性检验


剑指 Offer

剑指 Offer 32 - I. 从上到下打印二叉树

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

思路:
广度优先搜索。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] levelOrder(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        if (root == null) {
            return new int[]{};
        }
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
            list.add(node.val);
        }

        int[] res = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            res[i] = list.get(i);
        }
        return res;
    }
}

剑指 Offer 32 - II. 从上到下打印二叉树 II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

思路:
广度优先搜索。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
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 size = queue.size();
            List<Integer> temp = new ArrayList<>();

            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
                temp.add(node.val);
            }

            res.add(temp);
        }
        return res;
    }
}

剑指 Offer 32 - III. 从上到下打印二叉树 III

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

思路:
①按照之字形打印二叉树。广度搜索优先。取巧的方法,设置标志位,隔行对结果进行反转。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;

        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        List<Integer> temp = new ArrayList<>();
        boolean flag = true;

        while(!q.isEmpty()) {
            int size = q.size();
            temp.clear();
            for(int i = 0; i < size; i++) {
                TreeNode cur = q.poll();
                temp.add(cur.val);
                if(cur.left != null) q.add(cur.left);
                if(cur.right != null) q.add(cur.right);
            }
            if(flag) {
                res.add(new ArrayList(temp));
            } else {
                Collections.reverse(temp);
                res.add(new ArrayList(temp));
            }
            flag = !flag;
        }
        return res;
    }
}

②利用链表(更快)。当前res的大小为偶数时用addLast方法,为奇数时用addFirst实现倒序。对于第一层,res为0,从左向右;对于第二层,res为1,从右向左。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);

        while(!q.isEmpty()) {
            int size = q.size();
            LinkedList<Integer> temp = new LinkedList<>();
            for(int i = 0; i < size; i++) {
                TreeNode cur = q.poll();
                if (res.size() % 2 == 0) {
                    temp.addLast(cur.val);
                } else {
                    temp.addFirst(cur.val);
                }
                if(cur.left != null) q.add(cur.left);
                if(cur.right != null) q.add(cur.right);
            }
            res.add(temp);
        }
        return res;
    }
}

剑指 Offer 34. 二叉树中和为某一值的路径

输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

思路:
深度优先搜索。记录经过的节点,遍历到根节点时判断累加和是否为目标值。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        helper(new ArrayList<>(), res, root, sum);
        return res;
    }

    private void helper(List<Integer> list, List<List<Integer>> res, TreeNode root, int sum) {
        list.add(root.val);
        if (root.left == null && root.right == null) {
            int cur = 0;
            for (int n : list) {
                cur += n;
            }
            if (cur == sum) {
                res.add(new ArrayList<>(list));
                return;
            }
        }
        if (root.left != null) {
            helper(list, res, root.left, sum);
            list.remove(list.size() - 1);
        }
        if (root.right != null) {
            helper(list, res, root.right, sum);
            list.remove(list.size() - 1);
        }
    }
}

②深度优先搜索(更快)。利用链表。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    LinkedList<List<Integer>> res = new LinkedList();
    LinkedList<Integer> path = new LinkedList();

    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        recur(root,sum);
        return res;
    }

    private void recur(TreeNode root, int tar){
        if(root == null){
            return;
        }
        path.add(root.val);
        tar-=root.val;
        if(tar == 0 && root.left == null && root.right == null){
            res.add(new LinkedList(path));
        }

        recur(root.left,tar);
        recur(root.right,tar);

        path.removeLast();
    }
}