文章目录
层次遍历模板
理解使用队列进行二叉树层次遍历的过程
public List<Integer> levelOrder(TreeNode root){
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode node = queue.poll();
res.add(node.val);
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
return res;
}
层次遍历分层存储模版
层次遍历分层存储是解决下面问题的基础
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
List<Integer> list = new ArrayList<>();
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
list.add(node.val);
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
res.add(list);
}
return res;
}
层次遍历自底向上
按照层次遍历模版,将每层数据遍历结束后,将当前层存储到列表头部
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new LinkedList<List<Integer>>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(queue.size()>0){
int size = queue.size();
List<Integer> treeList = new ArrayList<Integer>();
for(int i=0;i<size;i++){
TreeNode treeNode = queue.poll();
treeList.add(treeNode.val);
if(treeNode.left!=null){
queue.add(treeNode.left);
}
if(treeNode.right!=null){
queue.add(treeNode.right);
}
}
res.add(0,treeList);
}
return res;
}
锯齿形层次遍历
设置一个遍历标识,用于判断是否是从左到右遍历,使用双端队列,根据遍历要求顺序,确定入队顺序
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
boolean fromLeftToRight = true;
while (!queue.isEmpty()) {
int size = queue.size();
Deque<Integer> treeList = new LinkedList<Integer>();
for(int i = 0; i < size; i++){
TreeNode treeNode = queue.poll();
if(fromLeftToRight){
treeList.offerLast(treeNode.val);
}else{
treeList.offerFirst(treeNode.val);
}
if(treeNode.left!=null){
queue.offer(treeNode.left);
}
if(treeNode.right!=null){
queue.offer(treeNode.right);
}
}
fromLeftToRight = !fromLeftToRight;
res.add(new LinkedList<>(treeList));
}
return res;
}
N叉树的层次遍历
与二叉树的层次遍历区别不大,区别在于二叉树的层次遍历是节点出队后,入队左右孩子,N叉树的层次遍历是节点出队后,入队所有子节点
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<Node> queue = new LinkedList<Node>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
List<Integer> nodeList = new ArrayList<>();
for(int i=0;i<size;i++){
Node node = queue.poll();
nodeList.add(node.val);
for(Node child:node.children){
queue.offer(child);
}
}
res.add(nodeList);
}
return res;
}
求二叉树每一层的最大值
遍历时,每一层设置一个保存最大值的变量,便利过程中不断更新该变量,最终得到每一层的最大值
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
int max = Integer.MIN_VALUE;
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
int val = node.val;
max = max>val?max:val;
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
res.add(max);
}
return res;
}
求二叉树每一层的平均值
与求每一层的最大值解法相同
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
double sum = 0;;
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
sum += node.val;
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
res.add(sum/size);
}
return res;
}
二叉树的右视图
便利每一层时,保存当前遍历的节点数等于队列size-1的节点,最终可以得到二叉树的右视图
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
double sum = 0;;
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
if(i==size-1){
res.add(node.val);
}
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
}
return res;
}
二叉树左下角的值
遍历时,一个节点出队时,先入队右孩子,在入队左孩子,这样最后一个访问到的节点就是二叉树左下角的值
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
int res = 0;
while(!queue.isEmpty()){
TreeNode node = queue.poll();
res = node.val;
if(node.right!=null){
queue.offer(node.right);
}
if(node.left!=null){
queue.offer(node.left);
}
}
return res;
}
二叉树前序遍历递归写法
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
preorderTraversal(root,res);
return res;
}
public void preorderTraversal(TreeNode root,List<Integer> res){
if(root==null){
return;
}
res.add(root.val);
preorderTraversal(root.left,res);
preorderTraversal(root.right,res);
}
二叉树中序遍历递归写法
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorderTraversal(root,res);
return res;
}
public void inorderTraversal(TreeNode root,List<Integer> res){
if(root==null){
return;
}
inorderTraversal(root.left,res);
res.add(root.val);
inorderTraversal(root.right,res);
}
二叉树后序遍历递归写法
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
postOrderTraversal(root,res);
return res;
}
public void postOrderTraversal(TreeNode root,List<Integer> res){
if(root==null){
return;
}
postOrderTraversal(root.left,res);
postOrderTraversal(root.right,res);
res.add(root.val);
}
二叉树前序遍历的迭代写法
使用栈按照根左右的方式进行二叉树的前序遍历
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stack = new LinkedList<TreeNode>();
while(root!=null || !stack.isEmpty()){
while(root!=null){
res.add(root.val);
stack.push(root);
root = root.left;
}
root = stack.pop();
root = root.right;
}
return res;
}
二叉树中序遍历的迭代写法
使用栈按照左根右的方式进行二叉树的中序遍历
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stack = new LinkedList<TreeNode>();
while(root!=null || !stack.isEmpty()){
while(root!=null){
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
二叉树后序遍历的迭代写法
使用栈按照根右左的方式进行二叉树的遍历,再将结果反转,即是二叉树的后续遍历
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Deque<TreeNode> stack = new LinkedList<TreeNode>();
while(root!=null || !stack.isEmpty()){
while(root!=null){
res.add(root.val);
stack.push(root);
root = root.right;
}
root = stack.pop();
root = root.left;
}
Collections.reverse(res);
return res;
}
判断两棵二叉树是否相同
比较两棵二叉树是否同时为空,同时为空相同,不同时为空不相同,同时不为空,在比较根节点和左右子树是否相同
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);
}
判断二叉树是否对称
判断二叉树是否为空,为空则对称,不为空比较左右子树是否对称
public boolean isSymmetric(TreeNode root) {
if(root==null){
return true;
}
return isSymmetric(root.left,root.right);
}
public boolean isSymmetric(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 isSymmetric(p.left,q.right)&&isSymmetric(p.right,q.left);
}
合并二叉树
判断是否至少有一棵二叉树为空,为空直接返回,两棵二叉树同时不为空,先合并根节点,然后再合并左右子树
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1==null || root2==null){
return root1==null?root2: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;
}
二叉树的所有路径
定义一个变量记录当前路径,定义一个列表存储所有路径,当当前节点的左右子树均为空,表明该路径到达终点,将该路径添加到路径列表中,否则当前路径加入该节点,继续递归查找当前节点的左右子树
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
searchPath(root,"",res);
return res;
}
public void searchPath(TreeNode root, String path, List<String> res){
if(root==null){
return;
}
if(root.left==null&&root.right==null){
path = path+root.val;
res.add(path);
return;
}
searchPath(root.left,path+root.val+"->",res);
searchPath(root.right,path+root.val+"->",res);
}
路径总和
每遍历一个节点,目标总和减去该节点值,当当前遍历节点的左右子树均为空时,判断当前节点值是否等于目标总和
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null){
return false;
}
targetSum-=root.val;
if(root.left==null&&root.right==null&&targetSum==0){
return true;
}
return hasPathSum(root.left,targetSum) || hasPathSum(root.right,targetSum);
}
反转二叉树
如果二叉树为空,直接返回。否则交换左右子节点,递归交换左右子树
public TreeNode invertTree(TreeNode root) {
if(root==null){
return root;
}
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
invertTree(root.left);
invertTree(root.right);
return root;
}
二叉树的最大深度
二叉树的最大深度等于左右子树的最大深度加一
public int maxDepth(TreeNode root) {
if(root==null){
return 0;
}
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left,right)+1;
}
public int maxDepth(TreeNode root) {
if(root==null){
return 0;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
int maxDepth = 0;
while(!queue.isEmpty()){
maxDepth++;
int size = queue.size();
for(int i=0;i<size;i++){
root = queue.poll();
if(root.left!=null){
queue.offer(root.left);
}
if(root.right!=null){
queue.offer(root.right);
}
}
}
return maxDepth;
}
二叉树的高度
二叉树的最大高度等于左右子树的最大高度加一
public int height(TreeNode root){
if(root==null){
return 0;
}
int leftHeight = height(root.left);
int rightHeight = height(root.right);
return Math.max(leftHeight,rightHeight)+1;
}
判断平衡树
计算左右子树的高度,判断高度差是否小于1
public boolean isBalanced(TreeNode root) {
if(root==null){
return true;
}
boolean rootBalanced = Math.abs(height(root.left)-height(root.right))<=1;
boolean leftBalanced = isBalanced(root.left);
boolean rightBalanced = isBalanced(root.right);
return rootBalanced&&leftBalanced&&rightBalanced;
}
public int height(TreeNode root){
if(root==null){
return 0;
}
int leftHeight = height(root.left);
int rightHeight = height(root.right);
return Math.max(leftHeight,rightHeight)+1;
}
public boolean isBalanced(TreeNode root) {
return height(root)>=0;
}
public int height(TreeNode root){
if(root==null){
return 0;
}
int leftHeight = height(root.left);
int rightHeight = height(root.right);
if(leftHeight==-1 || rightHeight== -1 || Math.abs(leftHeight-rightHeight)>1){
return -1;
}else{
return Math.max(leftHeight,rightHeight)+1;
}
}
最小深度
找到不为空的左子树和右子树的最小深度
public int minDepth(TreeNode root) {
if(root==null){
return 0;
}
if(root.left==null&&root.right==null){
return 1;
}
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if(root.left==null || root.right==null){
return leftDepth+rightDepth+1;
}
return Math.min(leftDepth,rightDepth)+1;
}
public int minDepth(TreeNode root) {
if(root==null){
return 0;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
int minDepth = 0;
while(!queue.isEmpty()){
minDepth++;
int size = queue.size();
for(int i=0;i<size;i++){
root = queue.poll();
if(root.left==null&&root.right==null){
return minDepth;
}
if(root.left!=null){
queue.offer(root.left);
}
if(root.right!=null){
queue.offer(root.right);
}
}
}
return minDepth;
}
N叉树的最大深度
与二叉树的最大深度原理相同
public int maxDepth(Node root) {
if(root==null){
return 0;
}
int maxDepth = 0;
for(Node node:root.children){
int depth = maxDepth(node);
if(depth>maxDepth){
maxDepth = depth;
}
}
return maxDepth+1;
}
最近公共祖先
在左右子树中寻找两个节点,如果两个节点在不同侧,则root就是最近公共祖先,在同侧,判断当前侧的根节点是否等于两个节点其中之一,相等则返回,否则在该侧的左右子树中继续寻找
private TreeNode res = null;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
dfs(root,p,q);
return res;
}
public boolean dfs(TreeNode root, TreeNode p,TreeNode q){
if(root==null){
return false;
}
boolean left = dfs(root.left,p,q);
boolean right = dfs(root.right,p,q);
if(left&&right){
res = root;
}
if(root == p || root ==q){
res = root;
}
return left || right || root==p || root==q;
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==p || root==q || root==null){
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;
}