我准备开始一个新系列【LeetCode题解】,用来记录刷题,顺便复习一下数据结构与算法。

1. 二叉树

二叉树(binary tree)是一种极为普遍的数据结构,树的每一个节点最多只有两个节点——左孩子结点与右孩子结点。C实现的二叉树:

struct TreeNode {int val;struct TreeNode *left; // left childstruct TreeNode *right; // right child
};

DFS

DFS的思想非常朴素:根据结点的连接关系,依次访问每一个节点,直至遍历完整棵树。根据根节点的访问次序的不同——前、中、后,可分为先序、中序、后序遍历。先序遍历是指先访问根节点,再依次访问左孩子节点、右孩子节点。下图给出一个二叉树的先序、中序、后序遍历示例:

递归实现:递归调用,打印根节点。C实现如下:

// preorder binary tree traversal
void preorder(struct TreeNode *root) {if(root) {printf("%d", root->val);preorder(root -> left);preorder(root -> right);}
}void inorder(struct TreeNode *root) {if(root) {inorder(root -> left);printf("%d", root->val);inorder(root -> right);}
}void postorder(struct TreeNode *root) {if(root) {postorder(root -> left);postorder(root -> right);printf("%d", root->val);}
}

任何递归实现的程序都可以改用栈实现。比如,先序遍历时用栈维护待访问结点;先将根结点入栈,再将右孩子结点入栈、左孩子结点入栈。Java实现如下:

public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) return result;Stack<TreeNode> stack = new Stack<>();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;
}

中序遍历,栈维护已访问结点。一个结点只有当其左孩子结点已访问时,才能出栈,然后入栈右孩子结点;否则,则入栈左孩子结点。

public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) return result;Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.peek();if (node.left != null) {stack.push(node.left);node.left = null; // its left child has been visited} else {result.add(node.val);stack.pop();if (node.right != null)stack.push(node.right);}}return result;
}

后序遍历,栈也维护已访问结点。一个结点只有当其左右孩子结点均已访问时,才能出栈;否则,则依次入栈右孩子结点、左孩子结点。

public List<Integer> postorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) return result;Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.peek();if (node.left == null && node.right == null) {result.add(node.val);stack.pop();} else {if (node.right != null) {stack.push(node.right);node.right = null; // its right child has been visited}if (node.left != null) {stack.push(node.left);node.left = null; // its left child has been visited}}}return result;
}

层次遍历

层次遍历为二叉树的BFS,是指按照结点的层级依次从左至右访问。实现层序遍历需要借助于队列,用以维护待访问的结点。

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

2. 题解

LeetCode题目 归类
100. Same Tree
101. Symmetric Tree
104. Maximum Depth of Binary Tree
111. Minimum Depth of Binary Tree
110. Balanced Binary Tree
112. Path Sum
113. Path Sum II
129. Sum Root to Leaf Numbers
144. Binary Tree Preorder Traversal 先序
94. Binary Tree Inorder Traversal 中序
145. Binary Tree Postorder Traversal 后序
102. Binary Tree Level Order Traversal 层次
107. Binary Tree Level Order Traversal II 层次
103. Binary Tree Zigzag Level Order Traversal 层次
114. Flatten Binary Tree to Linked List

100. Same Tree
判断两棵树是否一样,递归解决:

public boolean isSameTree(TreeNode p, TreeNode q) {if (p == null && q == null) return true;if (p == null || q == null) return false;return p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}

101. Symmetric Tree
同上一题较为类似,判断一棵树是否中心对称:

public boolean isSymmetric(TreeNode root) {return root == null || helper(root.left, root.right);
}private boolean helper(TreeNode p, TreeNode q) {if (p == null && q == null) return true;if (p == null || q == null) return false;return p.val == q.val && helper(p.left, q.right) && helper(p.right, q.left);
}

104. Maximum Depth of Binary Tree
二叉树的最大深度,递归实现之:

public int maxDepth(TreeNode root) {if (root == null) return 0;return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}

111. Minimum Depth of Binary Tree
二叉树的最小深度,解决思路与上类似,不过有个special case——根不能视作为叶子节点:

public int minDepth(TreeNode root) {if (root == null) return 0;if (root.left == null || root.right == null)return 1 + Math.max(minDepth(root.left), minDepth(root.right));return 1 + Math.min(minDepth(root.left), minDepth(root.right));
}

110. Balanced Binary Tree
判断一棵树是否平衡,即每一个节点的左右子树的深度不大于1,正好可用到上面求树深度的代码:

public boolean isBalanced(TreeNode root) {return root == null || Math.abs(maxDepth(root.left) - maxDepth(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);
}

112. Path Sum
判断root-to-leaf路径的结点之和是否存在,递归实现之:

public boolean hasPathSum(TreeNode root, int sum) {if (root == null) return false;if (root.val == sum && root.left == null && root.right == null) return true; // root is leaf nodereturn hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}

113. Path Sum II
上一个问题的变种,要将所有满足sum的情况保存下来;解决办法采用两个list存储中间结果,要注意list适当remove:

public List<List<Integer>> pathSum(TreeNode root, int sum) {List<List<Integer>> result = new LinkedList<>();List<Integer> pathList = new LinkedList<>(); // store a path which meets required sumhelper(root, sum, result, pathList);return result;
}private void helper(TreeNode root, int sum, List<List<Integer>> result, List<Integer> pathList) {if (root != null) {pathList.add(root.val);if (root.val == sum && root.left == null && root.right == null) {result.add(new LinkedList<>(pathList)); // deep copy} else {helper(root.left, sum - root.val, result, pathList);helper(root.right, sum - root.val, result, pathList);}pathList.remove(pathList.size() - 1); // remove the last element}
}

129. Sum Root to Leaf Numbers

二叉树的root-to-leaf路径表示一个十进制数,求所有路径所代表的数之和,递归实现:

public int sumNumbers(TreeNode root) {return helper(root, 0);
}private int helper(TreeNode root, int sum) {if (root == null) return 0; // special caseif (root.left == null && root.right == null) return sum * 10 + root.val;return helper(root.left, sum * 10 + root.val) + helper(root.right, sum * 10 + root.val);
}

144. Binary Tree Preorder Traversal
先序遍历,参看前面的栈实现。

94. Binary Tree Inorder Traversal
中序遍历,同上。

145. Binary Tree Postorder Traversal
后序遍历,同上。

102. Binary Tree Level Order Traversal
层次遍历,同上。

107. Binary Tree Level Order Traversal II
层次遍历变种,不同的是从bottom开始往上遍历;只需在层次遍历的代码中修改从头入result链表而不是从尾入:

result.addFirst(levelList);

103. Binary Tree Zigzag Level Order Traversa

“之”字形层次遍历,在层次遍历的基础上,将层级分为奇数、偶数,分别按顺序、逆序出队。

public List<List<Integer>> zigzagLevelOrder(TreeNode root) {List<List<Integer>> result = new LinkedList<>();if (root == null) return result;Queue<TreeNode> queue = new LinkedList<>();queue.add(root);int level = 1;while (!queue.isEmpty()) {int levelSize = queue.size();List<Integer> levelList = new LinkedList<>();while (levelSize-- > 0) { // to deal with level nodesTreeNode node = queue.poll();levelList.add(node.val);if (node.left != null) queue.add(node.left);if (node.right != null) queue.add(node.right);}if (level % 2 == 0) // be stack order when level is evenCollections.reverse(levelList);result.add(levelList);level++;}return result;
}

114. Flatten Binary Tree to Linked List
将二叉树打散成长链条树,从递归的角度来看,可分解为三个步骤:打散左子树,打散右子树,然后将右子树拼接到左子树尾部。

public void flatten(TreeNode root) {helper(root, null);
}// flatten sub-tree, return its root node
private TreeNode helper(TreeNode root, TreeNode last) {if (root == null) return last;root.right = helper(root.left, helper(root.right, last));root.left = null;return root;
}

转载于:https://www.cnblogs.com/en-heng/p/6349374.html

【LeetCode题解】二叉树的遍历相关推荐

  1. LeetCode题解——二叉树的堂兄弟节点

    LeetCode题解--二叉树的堂兄弟节点 题目介绍 解题思路 这题考察的就是树的遍历,其中带有2个条件遍历树 第一个条件记录下x和y出现的深度 第二个条件记录下x和y的父节点 当父节点不同xy深度相 ...

  2. leetcode题解(二叉树和递归问题)

    这篇博客我们主要来看二叉树和二叉树问题中使用递归来解决问题的思路.这类问题有时思路很简单,这是因为二叉树具有天然的递归结构,所以我们使用递归的解法解决二叉树有关的问题就变得非常明显. 二叉树天然的递归 ...

  3. leetcode 107 --- 二叉树程序遍历 ii

    1 题目 给定一个二叉树,返回该二叉树由底层到顶层的层序遍历,(从左向右,从叶子节点到根节点,一层一层的遍历) 2 解法 2.1 我的最初解法 按照正常的层序遍历应该是从上到下的,只要用一个栈先临时存 ...

  4. leetcode 144 --- 二叉树前序遍历

    1 题目 求给定的二叉树的前序遍历. 2 解法 2.1 递归解法 2.2 非递归解法 前序遍历,先遍历根节点,然后遍历左节点,最后是右节点,所以用栈的方式,先是根节点入栈,然后出栈遍历,如果该节点有左 ...

  5. 【LeetCode】专题一 二叉树层序遍历

    二叉树层序遍历 在本文中,我将会选取LeetCode上二叉树层序遍历的多道例题,并给出解答,通过多道题我们就可以发现,二叉树的层序遍历并不复杂,并且有着共通点. 102. 二叉树的层序遍历 给你二叉树 ...

  6. leetcode 257. 二叉树的所有路径(Java版)

    题目 https://leetcode-cn.com/problems/binary-tree-paths/ 题解 二叉树前序遍历即可 每走到一个节点,将当前节点的值拼到路径字符串 str 中. 如果 ...

  7. 【LeetCode题解】BFS层序遍历二叉树

    102.二叉树的层序遍历 分析: 层序遍历,顾名思义,就是按一层一层的顺序来对二叉树进行遍历,遍历顺序如下图所示 那么如何对二叉树进行遍历呢,我们首先将上面二叉树各层按照遍历次序放在同一直线上 现在我 ...

  8. 刻意练习:LeetCode实战 -- 二叉树的后序遍历

    背景 今天,第二期基础算法(Leetcode)刻意练习训练营 的打卡任务是二叉树的中序遍历,由于二叉树的遍历方式通常来说有四种:前序遍历.中序遍历.后序遍历以及层次遍历,而LeetCode也有二叉树的 ...

  9. 刻意练习:LeetCode实战 -- 二叉树的前序遍历

    背景 今天,第二期基础算法(Leetcode)刻意练习训练营 的打卡任务是二叉树的中序遍历,由于二叉树的遍历方式通常来说有四种:前序遍历.中序遍历.后序遍历以及层次遍历,而LeetCode也有二叉树的 ...

最新文章

  1. 【NeurIPS2021】存在潜在变量和选择偏差的递归因果结构学习
  2. 为jQuery的$.ajax设置超时时间
  3. 软考中高项学员:2016年3月14日作业
  4. [转]android使用shape stroke描边只保留底部
  5. minio安装及特性原理介绍
  6. 处理SAP Netweaver gateway service使用过程中遇到的404 error
  7. 设计模式(十五):解释器模式
  8. 信息学奥赛一本通(1068:与指定数字相同的数的个数)
  9. void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
  10. 翻译是不是计算机常用的颜色模式,关于颜色的翻译
  11. http转socks软件SOCKS2HTTP的使用
  12. Android 课程表
  13. WRF模式案例运行初体验--飓风示例全过程记录
  14. 国内 Mono 相关文章汇总
  15. 有什么压缩图片的方法?这里有两个方法分享
  16. Linux中su无法切换到目录,linux普通用户su root切换提示没有文件或目录的解决方法...
  17. java开发的颠覆者epub,创业颠覆者-陈景畑 翟顺[6寸pdf mobi epub kindle版].pdf
  18. VR全景展示+月子机构,多渠道流量获客
  19. MySQL基本知识点汇总 以及 高级查询练习
  20. SpringBoot实现Excel读取

热门文章

  1. mint java_Oracle Java 12 (JDK 12)在Ubuntu、Linux Mint或Debian(使用PPA)安装配置
  2. 加密芯片——RSA算法特点与应用注意事项
  3. 自动档汽车正确的操作方法和习惯---请教贴
  4. 为系统加载右键注册控件选项【VB 注册控件】
  5. VB在XP/2K 任务管理器的进程列表中隐藏当前进程
  6. 特斯拉自动驾驶遭遇中国性价比强敌!纽劢(mài)L3方案发布,成本1万3
  7. 最强读心术!脑波直接转语音,你的秘密已无处藏身 | Nature子刊
  8. 苹果、小米、荣耀智能手环都能测卫生纸心率?网友“测遍万物”玩坏了
  9. ARM发布自动驾驶芯片架构,重新宣示车载系统市场的主权
  10. 亚马逊狂发智能硬件新品:全新音箱、微波炉、挂钟、家庭卫士