题目描述(中等难度)

144. Binary Tree Preorder Traversal - 图1

二叉树的先序遍历。

思路分析

之前做过 94 题 的中序遍历,先序遍历的话代码可以直接拿过来用,只需要改一改 list.add 的位置。

解法一 递归

递归很好理解了,代码也是最简洁的。

  1. public List<Integer> preorderTraversal(TreeNode root) {
  2. List<Integer> list = new ArrayList<>();
  3. preorderTraversalHelper(root, list);
  4. return list;
  5. }
  6. private void preorderTraversalHelper(TreeNode root, List<Integer> list) {
  7. if (root == null) {
  8. return;
  9. }
  10. list.add(root.val);
  11. preorderTraversalHelper(root.left, list);
  12. preorderTraversalHelper(root.right, list);
  13. }

解法二 栈

第一种思路就是利用栈去模拟上边的递归。

  1. public List<Integer> preorderTraversal(TreeNode root) {
  2. List<Integer> list = new ArrayList<>();
  3. Stack<TreeNode> stack = new Stack<>();
  4. TreeNode cur = root;
  5. while (cur != null || !stack.isEmpty()) {
  6. if (cur != null) {
  7. list.add(cur.val);
  8. stack.push(cur);
  9. cur = cur.left; //考虑左子树
  10. }else {
  11. //节点为空,就出栈
  12. cur = stack.pop();
  13. //考虑右子树
  14. cur = cur.right;
  15. }
  16. }
  17. return list;
  18. }

第二种思路的话,我们还可以将左右子树分别压栈,然后每次从栈里取元素。需要注意的是,因为我们应该先访问左子树,而栈的话是先进后出,所以我们压栈先压右子树。

  1. public List<Integer> preorderTraversal(TreeNode root) {
  2. List<Integer> list = new ArrayList<>();
  3. if (root == null) {
  4. return list;
  5. }
  6. Stack<TreeNode> stack = new Stack<>();
  7. stack.push(root);
  8. while (!stack.isEmpty()) {
  9. TreeNode cur = stack.pop();
  10. if (cur == null) {
  11. continue;
  12. }
  13. list.add(cur.val);
  14. stack.push(cur.right);
  15. stack.push(cur.left);
  16. }
  17. return list;
  18. }

解法三 Morris Traversal

上边的两种解法,空间复杂度都是 O(n),利用 Morris Traversal 可以使得空间复杂度变为 O(1)

它的主要思想就是利用叶子节点的左右子树是 null ,所以我们可以利用这个空间去存我们需要的节点,详细的可以参考 94 题 中序遍历。

  1. public List<Integer> preorderTraversal(TreeNode root) {
  2. List<Integer> list = new ArrayList<>();
  3. TreeNode cur = root;
  4. while (cur != null) {
  5. //情况 1
  6. if (cur.left == null) {
  7. list.add(cur.val);
  8. cur = cur.right;
  9. } else {
  10. //找左子树最右边的节点
  11. TreeNode pre = cur.left;
  12. while (pre.right != null && pre.right != cur) {
  13. pre = pre.right;
  14. }
  15. //情况 2.1
  16. if (pre.right == null) {
  17. list.add(cur.val);
  18. pre.right = cur;
  19. cur = cur.left;
  20. }
  21. //情况 2.2
  22. if (pre.right == cur) {
  23. pre.right = null; //这里可以恢复为 null
  24. cur = cur.right;
  25. }
  26. }
  27. }
  28. return list;
  29. }

94 题 没什么差别,解法三利用已有空间去存东西,从而降低空间复杂度的思想经常用到。

windliang wechat

添加好友一起进步~

如果觉得有帮助的话,可以点击 这里 给一个 star 哦 ^^

如果想系统的学习数据结构和算法,强烈推荐一个我之前学过的课程,可以点击 这里 查看详情