迭代实现二叉树的遍历
144.二叉树的前序遍历
/**
* 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> res = new ArrayList<Integer>();
if(root == null) {
return res;
}
//辅助栈
Deque<TreeNode> stack = new LinkedList<TreeNode>();
//
TreeNode cur = root;
while(!stack.isEmpty() || node != null) {
//一路向左下处理
while(node != null) {
res.add(node.val);
stack.push(node);
node = node.left;
}
//当没有左孩子时,取出栈中的节点,向右孩子处理
//下一次循环即为,处理右子树
node = stack.pop();
node = node.right;
}
}
}
94.二叉树的中序遍历
/**
* 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> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if(root == null) {
return res;
}
//辅助栈
Deque<TreeNode> stack = new LinkedList<TreeNode>();
//
TreeNode node = root;
//首次进入循环,会出现stack为空的情况
while(!stack.isEmpty() || node != null) {
//一路向左下,不访问
while(node != null) {
stack.push(node);
node = node.left;
}
//核心
//如果节点没有右子树(node = node.right,之后由第一个循环进行判断)
//说明以该节点作为根节点的树,已经遍历结束
//会继续回溯
node = stack.pop();
res.add(node.val);
node = node.right;
}
return res;
}
}
145.二叉树的后序遍历
/**
* 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> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if(root == null) {
return res;
}
//辅助栈
Deque<TreeNode> stack = new LinkedList<TreeNode>();
//
TreeNode pre = root;
while(!stack.isEmpty() || root != null) {
while(root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
//当前没有左子树了,判断是处理右子树,还是处理当前节点
//右子树已经遍历过的两种情况:
//没有右子树
//右子树刚刚被遍历
if(root.right == null || pre == root.right) {
//访问节点
res.add(root.val);
//记录上一个访问的节点
pre = root;
//这里有个大坑
//每次遍历完左子树
//如果不做置空操作
//则会重新入栈左子树
root = null;
} else {
//处理右子树
//将当前节点入栈
//root指向右子树根节点
stack.push(root);
root = root.right;
}
}
return res;
}
}
树的经典算法
100.相同的树
/**
* 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 boolean isSameTree(TreeNode p, TreeNode q) {
//若树为空则相同
if(p == null && q == null) {
return true;
}
//若任意一个为空则不相同
if(p == null || q == null) {
return false;
}
//值不相同则不相同
if(p.val != q.val) {
return false;
}
//左右子树均相同
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
101.对称树
/**
* 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 boolean isSymmetric(TreeNode root) {
if(root.left == null && root.right == null) return true;
return isSymmetric1(root.left, root.right);
}
public boolean isSymmetric1(TreeNode q, TreeNode p) {
//结构对称
//均为空,则对称
if(q == null && p == null) {
return true;
}
//任一为空,则不对称
if(q == null || p == null) {
return false;
}
//数值对称
//左孩子等于右孩子,则对称
if(p.val != q.val) {
return false;
}
return isSymmetric1(q.left, p.right) && isSymmetric1(q.right, p.left);
}
}
617.合并树
/**
* 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 TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1 == null) {
return root2;
}
if(root2 == null) {
return root1;
}
TreeNode merged = new TreeNode(root1.val + root2.val);
merged.left = mergeTrees(root1.left, root2.left);
merged.right = mergeTrees(root1.right, root2.right);
return merged;
}
}
路径问题
257.二叉树的所有路径
递归算法
/**
* 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<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<String>();
dfs(root, "", res);
return res;
}
void dfs(TreeNode root, String path, List<String> res) {
if(root == null) return;
//叶节点
if(root.left == null && root.right == null) {
res.add(path + root.val);
return;
}
//路径的扩展,通过传参的方式
dfs(root.left, path + root.val + "->", res);
dfs(root.right, path + root.val + "->", res);
}
}
迭代算法
回溯算法的入门,后续补充
112.路径总和
/**
* 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 boolean hasPathSum(TreeNode root, int sum) {
if(root == null) {
return false;
}
//进入根节点后,若 sum == root.val则为真
if(root.left == null && root.right == null) {
return sum == root.val;
}
boolean left = hasPathSum(root.left, sum - root.val);
boolean right = hasPathSum(root.right, sum - root.val);
return left || right;
}
}
226.翻转二叉树
/**
* 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 TreeNode invertTree(TreeNode root) {
if(root == null) {
return null;
}
if(root.left != null || root.right != null) {
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
invertTree(root.left);
invertTree(root.right);
return root;
}
}
深度问题
104.最大深度
递归
/**
* 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 int maxDepth(TreeNode root) {
//每层节点返回当前深度
//还要有大小比较
//应该要有一个参数来传递当前的深度
return getMaxDepth(root, 1);
}
//depth为当前的深度
public int getMaxDepth(TreeNode root, int depth) {
//处理到空节点返回0
if(root == null) {
return 0;
}
//若处理到叶子节点,则返回当前深度
if(root.left == null && root.right == null) {
return depth;
}
//返回深度的最大值
return getMax(getMaxDepth(root.left, depth + 1), getMaxDepth(root.right, depth + 1));
}
public int getMax(int a, int b) {
return a > b ? a : b;
}
}
还有更简洁的代码
public int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
int leftDepth = maxDepth(root.left);
int rightDepth = maxDepth(root.right);
return max(leftDepth, rightDepth) + 1;
}
迭代
本质是层次遍历,计算层数
/**
* 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 int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
Deque<TreeNode> queue = new LinkedList<TreeNode>();
queue.addLast(root);
int ans = 0;
while(!queue.isEmpty()) {
//上一次循环中,获取的一层的节点数
int size = queue.size();
ans++;
for(int i = 0; i < size; i++) {
//出队
TreeNode tmp = queue.pollFirst();
//子节点入队
if(tmp.left != null) {
queue.addLast(tmp.left);
}
if(tmp.right != null) {
queue.addLast(tmp.right);
}
}
}
return ans;
}
}
110.判断平衡二叉树
我写了一段错误代码,分享出来
class Solution {
public boolean isBalanced(TreeNode root) {
//本质:左右子树最大深度之差是否小于1
if(root == null) {
return true;
}
int leftDepth = getMaxDepth(root.left);
int rightDepth = getMaxDepth(root.right);
int flag = Math.abs(leftDepth - rightDepth);
return flag <= 1;
}
public int getMaxDepth(TreeNode root) {
if(root == null) return 0;
int leftDepth = getMaxDepth(root.left);
int rightDepth = getMaxDepth(root.right);
return Math.max(leftDepth, rightDepth) + 1;
}
}
这段代码的逻辑问题在于,只判断了当前节点的左右子树的最大深度差是否小于等于1,但没有判断左右子树本身是否是平衡二叉树。
在判断平衡二叉树时,需要同时满足两个条件:
- 当前节点的左右子树高度差不超过1。
- 当前节点的左子树和右子树都是平衡二叉树。
以下是正确代码
class Solution {
public boolean isBalanced(TreeNode root) {
//本质:左右子树最大深度之差是否小于1,再判断左右子树也是平衡二叉树
if(root == null) {
return true;
}
int leftDepth = getMaxDepth(root.left);
int rightDepth = getMaxDepth(root.right);
int depthDiff = Math.abs(leftDepth - rightDepth);
if(depthDiff > 1) return false;
boolean leftBalanced = isBalanced(root.left);
boolean rightBalanced = isBalanced(root.right);
return leftBalanced && rightBalanced;
}
public int getMaxDepth(TreeNode root) {
if(root == null) return 0;
int leftDepth = getMaxDepth(root.left);
int rightDepth = getMaxDepth(root.right);
return Math.max(leftDepth, rightDepth) + 1;
}
}
优化
上面的代码,在每个节点上都进行了重复的递归计算,可以通过对每个节点记录其高度的方式来避免重复计算。
class Solution {
public boolean isBalanced(TreeNode root) {
return checkHeight(root) != -1;
}
private int checkHeight(TreeNode root) {
if (root == null) {
return 0;
}
int leftHeight = checkHeight(root.left);
if (leftHeight == -1) {
return -1;
}
int rightHeight = checkHeight(root.right);
if (rightHeight == -1) {
return -1;
}
int heightDiff = Math.abs(leftHeight - rightHeight);
if (heightDiff > 1) {
return -1;
}
return Math.max(leftHeight, rightHeight) + 1;
}
}
111.最小深度
/**
* 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 int minDepth(TreeNode root) {
if(root == null) {
return 0;
}
if(root.left == null && root.right == null) {
return 1;
}
int min_depth = Integer.MAX_VALUE;
if(root.left != null) {
min_depth = Math.min(minDepth(root.left), min_depth);
}
if(root.right != null) {
min_depth = Math.min(minDepth(root.right), min_depth);
}
return min_depth + 1;
}
}
共同祖先
236.最近公共组选
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left == null && right == null) return null;
if(left == null) return right;
if(right == null) return left;
return root;//if(left != null && right != null)
}
}