二叉树算法总结
二叉树的遍历方式
##基础数据结构
class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val){
this.val = val;
this.left = null;
this.right = null;
}
public TreeNode getLeft() {
return left;
}
public void setLeft(TreeNode left) {
this.left = left;
}
public TreeNode getRight() {
return right;
}
public void setRight(TreeNode right) {
this.right = right;
}
}
前序
根节点->左子树->右子树**(根->左->右)**
static void preTraversal(TreeNode root){
if(root!=null){
//在访问该节点直接输出
System.out.println(root.val);
preTraversal(root.left);
preTraversal(root.right);
}
}
中序
左子树->根节点->右子树**(左->根->右)**
static void preTraversal(TreeNode root){
if(root!=null){
preTraversal(root.left);
//在访问节点左孩子之后直接输出
System.out.println(root.val);
preTraversal(root.right);
}
}
后序
左子树->右子树->根节点**(左->右->根)**
static void preTraversal(TreeNode root){
if(root!=null){
preTraversal(root.left);
preTraversal(root.right);
//在访问节点右孩子之后直接输出
System.out.println(root.val);
}
}
leedCode 113路径总和
求一棵二叉树的路径等于sum的值。思路深度优先遍历,记录路径长度总和,等于sum加入res.
注意事项:
- 必须在叶子节点,所以判断的时候加上该节点是不是叶子节点
- 添加结果的时候要新定义一个list,深拷贝
- 如果该路径不符合,回溯。
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> res = new LinkedList<>();
pathSumHelper(root,sum,res,new LinkedList<>(),0);
return res;
}
public static void pathSumHelper(TreeNode root,int sum,List<List<Integer>> res,LinkedList<Integer> subRes,int total){
if(root == null){
return;
}
total+=root.val;
subRes.add(root.val);
//添加符合,深拷贝
if(total==sum && root.left==null&&root.right==null){
res.add(new LinkedList(subRes));
}
pathSumHelper(root.left,sum,res,subRes,total);
pathSumHelper(root.right,sum,res,subRes,total);
//路径不符合回溯
total-= root.val;
subRes.removeLast();
}
}
leedCode 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) {
LinkedList<TreeNode> pP = new LinkedList<TreeNode>();
LinkedList<TreeNode> qP = new LinkedList<TreeNode>();
TreeNode res = new TreeNode(0);
search(root,p,new LinkedList<>(),pP,0);
search(root,q,new LinkedList<>(),qP,0);
int path_length = pP.size()>qP.size()?qP.size():pP.size();
for(int i=0; i<path_length;i++){
if(pP.get(i)==qP.get(i)){
res = (TreeNode)pP.get(i);
}
}
return res;
}
public static void search(TreeNode root,TreeNode target,LinkedList<TreeNode> temp,LinkedList<TreeNode> res, int finish){
if(root== null || finish==1 ){
return;
}
//添加父亲节点
temp.add(root);
//如果找到目标,标记完成标志,剪枝,并把之前添加的父亲节点加入结果集合
if(root == target){
finish=1;
res.addAll(temp);
}
search(root.left,target,temp,res,finish);
search(root.right,target,temp,res,finish);
//这里要删除遍历过程中的叶子节点,这里也会删除掉每一个节点,所以我们在找到目标后进行了拷贝
temp.removeLast();
}
}
LeedCode114. 二叉树展开为链表
思路:
- 变成链表的顺序就是树先序遍历的顺序,还有就是可以看到的一种规律是树的左子树变成了右子树,而右子树变成了左子树最后一个右子树的后序节点。
- 那么我们的大概算法就是从根节点遍历它的左子树,如果左子树为空,根等于它的右子树(这里在判断它的左子树是不是为空),如果不为空,遍历这个左子树的最后一个右孩子,然后让根节点的右孩子等于根节点的左孩子,让根节点左孩子的最后一个右孩子的右孩子等于根节点的右孩子。之后根节点变成了根节点的右孩子。
class Solution {
public void flatten(TreeNode root) {
while(root != null){
//判断根节点的左孩子是不是null
if(root.left == null){
//如果为空,遍历根的下一个右孩子
root = root.right;
}else{
//不为空,记录根的左孩子副本
TreeNode pre = root.left;
//找到左孩子的最后一个右孩子
while(pre.right!=null){
pre = pre.right;
}
//将根节点的右孩子连接到根节点左孩子的最后一个右孩子的右边
pre.right = root.right;
//将根节点的右孩子变成左孩子
root.right = root.left;
//让根节点左孩子为空,变成单链表
root.left = null;
//根节点迭代,变成第二个右孩子了
root = root.right;
}
}
}
}
LeedCode 199. 二叉树的右视图
思路:其实它的根本就是层次遍历二叉树,然后每一层都保留最右边的节点。
关键点:
- 树的层次遍历
- 找到每一层最后的一个节点,这个也可以理解为怎么判断遍历到树的第几层
public List<Integer> rightSideView(TreeNode root) {
//用于树的层次遍历,实现队列的功能,将每一层的根节点和左孩子右孩子依次添加进去
//然后在一个新的添加之前弹出队列最前面的节点
LinkedList<Map<Integer,TreeNode>> queueNode = new LinkedList<>();
//记录树的深度
int maxDeep = -1;
//记录树的深度和该层最右边节点的值
Map<Integer,Integer> deepAndVal = new HashMap<>();
if(root != null){
Map<Integer,TreeNode> temp = new HashMap<>();
temp.put(0,root);
queueNode.add(temp);
}
//遍历节点队列,直到非空为止
while(queueNode.size()!= 0){
//移除队首节点
Map<Integer,TreeNode> head = queueNode.removeFirst();
//获取需要处理的树几点
Map.Entry<Integer,TreeNode> val = head.entrySet().iterator().next();
//获取该节点的深度
int deep = val.getKey();
//获取该节点的值
TreeNode td = val.getValue();
//把这个深度的这个值 放到结果map,这里一直替换值得。
deepAndVal.put(deep,td.val);
maxDeep = Math.max(maxDeep,deep);
if(td.left != null){
Map<Integer,TreeNode> temp = new HashMap<>();
temp.put(deep+1,td.left);
queueNode.add(temp);
}
if(td.right != null){
Map<Integer,TreeNode> temp = new HashMap<>();
temp.put(deep+1,td.right);
queueNode.add(temp);
}
}
//遍历map 生成list
List<Integer> res = new ArrayList<>();
for(int i = 0; i < maxDeep+1; i++){
res.add(deepAndVal.get(i));
}
return res;
}