我不害怕曾經練過一萬種踢法的人,但我害怕一種踢法練過一萬次的人(by 叶师傅的徒弟Bruce Lee)
树的遍历(Traversal)
如下图, 三种遍历方式, 可用同一种递归思想实现
1. 144. 先序遍历(PreOrder, 按照先访问根节点的顺序)
示例 1:
1
\
2
/
3
输入:root = [1,null,2,3]
输出:[1,2,3]
解法
/*
* @lc app=leetcode.cn id=144 lang=java
*
* [144] 二叉树的前序遍历
*/
// @lc code=start
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
dfs(root, list);
return list;
}
private void dfs(TreeNode root, List<Integer> list) {
if (root == null) return;
list.add(root.val);
dfs(root.left, list);
dfs(root.right, list);
}
}
// @lc code=end
2. 94 中序遍历(InOrder, 按照根节点在中间访问的顺序)
给定一个二叉树的根节点 root ,返回它的 中序 遍历。
示例:
1
\
2
/
3
输入:root = [1,null,2,3]
输出:[1,3,2]
解法
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
dfs(root, list);
return list;
}
private void dfs(TreeNode root, List<Integer> list) {
if (root == null) return;
dfs(root.left, list);
list.add(root.val);
dfs(root.right, list);
}
}
3. 145 后续遍历(PosterOrder, 按照根节点在后面访问的顺序)
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [3,2,1]
解法
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
dfs(root, list);
return list;
}
private void dfs(TreeNode root, List<Integer> list) {
if (root == null) return;
dfs(root.left, list);
dfs(root.right, list);
list.add(root.val);
}
}
4. 100. 相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
输入:p = [1,2,3], q = [1,2,3]
输出:true
解法
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if ((p == null && q != null) || (p != null && q == null)) return false;
if (p == null && q == null) return true;
return p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
5. 226 翻转二叉树
翻转一棵二叉树。
示例:
输入:
4
/ \
2 7
/ \ / \
1 3 6 9
输出:
4
/ \
7 2
/ \ / \
9 6 3 1
备注:
这个问题是受到 Max Howell 的 原问题 启发的 :
谷歌:我们90%的工程师使用您编写的软件(Homebrew),但是您却无法在面试时在白板上写出翻转二叉树这道题,这太糟糕了。
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return root;
TreeNode left = root.left;
TreeNode right = root.right;
root.left = invertTree(right);
root.right = invertTree(left);
return
}
}
6. 590. N 叉树的后序遍历
给定一个 N 叉树,返回其节点值的 后序遍历 。
N 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。
进阶:
递归法很简单,你可以使用迭代法完成此题吗?
示例 1:
输入:root = [1,null,3,2,4,null,5,6]
输出:[5,6,3,2,4,1]
解法
/*
* @lc app=leetcode.cn id=590 lang=java
*
* [590] N 叉树的后序遍历
*/
// @lc code=start
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<Integer> postorder(Node root) {
List<Integer> list = new ArrayList<>();
dfs(root, list);
return list;
}
private void dfs(Node root, List<Integer> list) {
if (root == null) return;
for(Node node: root.children) {
dfs(node, list);
}
list.add(root.val);
}
}
// @lc code=end
7. 103. 二叉树的锯齿形层序遍历
给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回锯齿形层序遍历如下:
[
[3],
[20,9],
[15,7]
]
解法:
/*
* @lc app=leetcode.cn id=103 lang=java
*
* [103] 二叉树的锯齿形层序遍历
*/
// @lc code=start
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) {
return result;
}
boolean isLeftToRight = true;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Deque<Integer> levelDeque = new LinkedList<>();
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (isLeftToRight) {
levelDeque.offerLast(node.val);
} else {
levelDeque.offerFirst(node.val);
}
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(new LinkedList<Integer>(levelDeque));
isLeftToRight = !isLeftToRight;
}
return result;
}
}
// @lc code=end
8. 230. 二叉搜索树中第K小的元素
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。
示例 1:
3
/ \
1 4
\
2
输入:root = [3,1,4,null,2], k = 1
输出:1
中序遍历
class Solution {
public int kthSmallest(TreeNode root, int k) {
List<Integer> list = new ArrayList<>();
dfs(root, k, list);
return list.get(k - 1);
}
private void dfs(TreeNode root, int k, List<Integer> list) {
if (root == null || list.size() == k) return;
dfs(root.left, k, list);
list.add(root.val);
dfs(root.right, k, list);
}
}
9. 102. 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层序遍历结果:
[
[3],
[9,20],
[15,7]
]
递归 + 前序遍历的解法,记录每一层的高度值。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
dfs(root, 0, result);
return result;
}
private void dfs(TreeNode root, int level, List<List<Integer>> result) {
if (root == null) return;
if (result.size() == level) {
result.add(new ArrayList<Integer>());
}
result.get(level).add(root.val);
dfs(root.left, level + 1, result);
dfs(root.right, level + 1, result);
}
}
10. 199. 二叉树的右视图
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例:
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:
1 <---
/ \
2 3 <---
\ \
5 4 <---
基本思路: 先序遍历, 记录每一层深度下的节点的值, 并先记录左节点再记录右节点, 则最后记录的值即为该层深度的右视图看到的值
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<List<Integer>> allList = new ArrayList<>();
List<Integer> list = new ArrayList<>();
if (root == null) return list;
dfs(root, 0, allList);
for (int i = 0; i < allList.size(); i++) {
list.add(allList.get(i).get(allList.get(i).size() - 1));
}
return list;
}
private void dfs(TreeNode root, int level, List<List<Integer>> allList) {
if (root == null) return;
if (level == allList.size()) allList.add(new ArrayList<Integer>());
allList.get(level).add(root.val);
dfs(root.left, level + 1, allList);
dfs(root.right, level + 1, allList);
}
}
11. 104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
class Solution {
public int maxDepth(TreeNode root) {
return root == null ? 0 : 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}
}
12. 107. 二叉树的层序遍历 II
给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其自底向上的层序遍历为:
[
[15,7],
[9,20],
[3]
]
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> reverse = new ArrayList<>();
dfs(root, 0, reverse);
List<List<Integer>> result = new ArrayList<>();
for (List<Integer> list: reverse) {
result.add(0, list);
}
return result;
}
private void dfs(TreeNode root, int level, List<List<Integer>> result) {
if (root == null) return;
if (result.size() == level) result.add(new ArrayList<Integer>());
result.get(level).add(root.val);
dfs(root.left, level + 1, result);
dfs(root.right, level + 1, result);
}
}
参考
https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/solution/yi-tao-quan-fa-shua-diao-nge-bian-li-shu-de-wen–3/