总体思路
在二叉树的题目中,一大半是可以通过遍历一遍整棵树解决的,模板如下
void traverse(TreeNode root){
if (root == null) return;
// 刚进入
traverse(root.left);
// 左转右
traverse(root.right);
// 离开时
明确对每个节点做什么操作+在三个时间点中什么时候操作即可
下面的所有题目都是套这个模板
经典三遍历
分别把访问节点的操作放到递归函数的三个位置
前序
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
traverse(root);
return res;
}
void traverse(TreeNode root){
if (root == null) return;
// 刚进入
res.add(root.val);
traverse(root.left);
// 左转右
traverse(root.right);
// 离开时
}
}
中序
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
traverse(root);
return res;
}
void traverse(TreeNode root){
if (root == null) return;
// 刚进入
traverse(root.left);
// 左转右
res.add(root.val);
traverse(root.right);
// 离开时
}
}
后序
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> postorderTraversal(TreeNode root) {
traverse(root);
return res;
}
void traverse(TreeNode root){
if (root == null) return;
// 刚进入
traverse(root.left);
// 左转右
traverse(root.right);
// 离开时
res.add(root.val);
}
}
N叉树的遍历
N叉树没法中序遍历,两个切入点在递归前和递归后
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> preorder(Node root) {
traverse(root);
return res;
}
void traverse(Node root){
if (root == null) return;
// 刚进入
res.add(root.val);
for (Node child : root.children) traverse(child);
// 离开时
}
}
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> postorder(Node root) {
traverse(root);
return res;
}
void traverse(Node root){
if (root == null) return;
// 刚进入
for (Node child : root.children) traverse(child);
// 离开时
res.add(root.val);
}
}
深度问题
class Solution {
int res = 0, len = 0;
public int maxDepth(TreeNode root) {
traverse(root);
return res;
}
void traverse(TreeNode root){
if (root == null) return;
// 刚进入
len++;
if (root.left == root.right) res = Math.max(res,len);
traverse(root.left);
// 左转右
traverse(root.right);
// 离开时
len--;
}
}
class Solution {
int res = 0, len = 0;
public int maxDepth(Node root) {
traverse(root);
return res;
}
void traverse(Node root){
if (root == null) return;
// 刚进入
len++;
if (root.children.size() == 0) res = Math.max(res,len);
for (Node child : root.children) traverse(child);
// 离开时
len--;
}
}
class Solution {
int res = 100000, len = 0;
public int minDepth(TreeNode root) {
if (root == null) return 0;
traverse(root);
return res;
}
void traverse(TreeNode root){
if (root == null) return;
// 刚进入
len++;
if (root.left == root.right) res = Math.min(res,len);
traverse(root.left);
// 左转右
traverse(root.right);
// 离开时
len--;
}
}
路径和
class Solution {
int sum = 0;
boolean flag = false;
public boolean hasPathSum(TreeNode root, int targetSum) {
traverse(root,targetSum);
return flag;
}
void traverse(TreeNode root, int targetSum){
if (root == null) return ;
// 刚进入
sum += root.val;
if (root.left == root.right && sum == targetSum) flag = true;
traverse(root.left,targetSum);
// 左转右
traverse(root.right,targetSum);
// 离开时
sum -= root.val;
}
}
纯纯语法题,res.add(new ArrayList<>(path))这里必须传副本,直接传path的话因为传的是引用,后续path的改变会影响到容器res
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
int sum = 0;
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
traverse(root,targetSum);
return res;
}
void traverse(TreeNode root, int targetSum) {
if (root == null) return ;
// 刚进入
sum += root.val;
path.add(root.val);
if (root.left == root.right && sum == targetSum) res.add(new ArrayList<>(path));
traverse(root.left,targetSum);
// 左转右
traverse(root.right,targetSum);
// 离开时
sum -= root.val;
path.remove(path.size()-1);
}
}
翻转二叉树
class Solution {
public TreeNode invertTree(TreeNode root) {
traverse(root);
return root;
}
void traverse(TreeNode root){
if (root == null) return;
// 刚进入
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
traverse(root.left);
// 左转右
traverse(root.right);
// 离开时
}
}
class Solution {
int sum = 0;
public int sumOfLeftLeaves(TreeNode root) {
traverse(root);
return sum;
}
void traverse(TreeNode root){
if (root == null) return;
// 刚进入
if (root.left != null && root.left.left == root.left.right) sum += root.left.val;
traverse(root.left);
// 左转右
traverse(root.right);
// 离开时
}
}