判定两棵树是否互为镜像对称的树
/**
* @Description: 判定两棵树是否互为镜像对称的树
* @Param: A的左子树和B右子树互为镜像,
* @return:
*/
public boolean isMirror(Node p, Node q) {
if (p == null && q == null) {
return true;
} else if (p == null || q == null) {
return false;
}
return p.val == q.val
&& isMirror(p.left, q.right)
&& isMirror(p.right, q.left);
}
判断一棵树自己是否是镜像对称的
/**
* @Description: 判断一棵树自己是否是镜像对称的
* @Param:
* @return:
*/
public boolean isSelfMiiro(Node root){
if(root==null){
return true;
}
return isMirror(root.left,root.right);
}
平衡二叉树:左子树与右子树深度相差<1 左右子数高度差不超过1
/**
* @Description: 平衡二叉树:左子树与右子树深度相差<1 左右子数高度差不超过1
* soulution:遍历左子树的
* @return:
*/
public boolean isBalanced(Node root) {
if(root==null){
return true;
}
if(!(isBalanced(root.left))){
return false;
}
if(!(isBalanced(root.right))){
return false;
}
//每层都逐一计算左子树和右子树的高度
//然后计算高度差
//一旦有一层不符合就返回false
int left=hight(root.left);
int right=hight(root.right);
int diff=left-right;
if(diff>1||diff<-1){
return false;
}
return true;
}
private int hight(Node root) {
if(root!=null){
int left=hight(root.left)+1;
int right=hight(root.right)+1;
return left>right ? left:right;
}
return 0;
}
判断一棵树是否是另一个树的子树
/**
* @Description: 另一个树的子树
* @Param:
* @return:
*/
public boolean isSubtree(Node s, Node t) {
return findTree(s,t);
}
private boolean findTree(Node root,Node t){
if(root==null && t==null){
return true;
}
if(root==null ){
return false;
}
if(isEqual(root,t)){
return true;
}
if(findTree(root.right,t)){
return true;
}
return findTree(root.left,t);
}
创建二叉树
/**
* @Description: 创建二叉树
* 不能用普通的前序遍历创建二叉树
* 用带空节点的前序遍历创建二叉树
* class RV{
* Node root;
* int used;
* }
* public RV createTree(整棵树的前序){
* if(整个树的长度为0){
* return RV={NULL.0};
* }
* 1. 根的值=前序[0];
* if(rootValue==#){
* 创建的树是空树,当前创建子树的根节点为null,用了一个节点
* }
*
* 左子树(root.left),左子树使用的个数=createTree(整棵树的前序除去char[0])
* 右子树(root.right),右子树使用的个数=cratTree(整棵树的前序除去第一个和左子树用掉的)
* return{root,根使用的个数+左子树使用的个数+右子树使用的个数}
* }
*/
class ReturnRoot{
private Node nowRoot;
private int used;
public ReturnRoot(Node nowRoot, int used) {
this.nowRoot = nowRoot;
this.used = used;
}
}
public ReturnRoot creatTree(char[] preOrder){
if(preOrder.length==0){
//如果前序数组长度为0,说明没有树可以创建
return new ReturnRoot(null,0);
}
//如果长度不为0,则取出第一个节点为根节点
if(preOrder[0]=='#'){
//若根节点为空,则返回根节点为空,使用了1个空节点
return new ReturnRoot(null,1);
}else{
Node root= new Node(preOrder[0]);
//第一个数组元素作为根节点,利用剩余数组继续创建树的左子树
char [] restLeft=Arrays.copyOfRange(preOrder,1,preOrder.length);
//递归调用创建树,返回值为ReturnRoot
ReturnRoot leftReturn=creatTree(restLeft);
//左子树创建完后创建右子树,右子树的长度为整棵树的前序除去第一个和左子树用掉的
char[] restRight=Arrays.copyOfRange
(preOrder,preOrder.length-leftReturn.used,preOrder.length);
//递归调用创建右子树,返回值为ReturnRoot
ReturnRoot rightRoot=creatTree(restRight);
//把根,左子树,右子树链接在一起
root.left=leftReturn.nowRoot;
root.right=rightRoot.nowRoot;
//返回值为根节点,用了的长度为根+左子树用了的+右子树用了的
return new ReturnRoot(root,1+leftReturn.used+rightRoot.used);
}
}
利用前序和中序构建二叉树
/**
* @Description: 利用前序+中序构建二叉树
* 1在前序中找到根的值 preOrder[0]
* 2在中序中找到根的值所在的下标--》可得到左子树的节点个数
* 3.切出左子树的前序+中序 :preOder跳过1,长度是下标; inOrder,长度是下标
* 4.切出右子树的前序+中序:preOder跳过1,跳过下标(到达右子树),长度为总长-左子树长度
* inOrder:跳过下标,跳过1,长度为总长-下标
*/
public TreeNode buildTree12(int[] preorder, int[] inorder) {
if (preorder == null) {
return null;
}
//1.在前序中找到根的值
TreeNode root = new TreeNode(preorder[0]);
//2.在中序中找到根所在的下标==左子树的节点个数
int leftSize = -1;
for (int i = 0; i < inorder.length; i++) {
if (inorder[i] == preorder[0]) {
leftSize = i;
}
}
//前序:ABCDE
//中序:CDBAE
//3.切出左子树的前序:copyOfRange()函数参数的区间--左闭右开
int[] leftPreOrder = Arrays.copyOfRange(preorder, 1, leftSize + 1);
//切出左子树的中序
int[] leftInOrder = Arrays.copyOfRange(inorder, 0, leftSize);
TreeNode rootLeft = buildTree12(leftPreOrder, leftInOrder);
//4.切出右子树的前序
int[] rightPreOrder = Arrays.copyOfRange(preorder, leftSize + 1, preorder.length);
//切出右子树的中序
int[] rightInOrder = Arrays.copyOfRange(inorder, leftSize + 1, inorder.length);
TreeNode rightRoot = buildTree12(rightPreOrder, rightInOrder);
root.left = rootLeft;
root.right = rightRoot;
return root;
}
利用中序和后续构建二叉树
/**
* @Description: 通过中序和后序遍历构建二叉树
* @Param:
* @return:
*/
public TreeNode buildTree23(int[] inorder, int[] postorder) {
if (inorder.length == 0) {
return null;
}
//1.在后序中找到根节点
TreeNode root = new TreeNode(postorder[postorder.length - 1]);
//2.得到左子树的长度
int leftSize = -1;
for (int i = 0; i < inorder.length; i++) {
if (inorder[i] == root.val) {
leftSize = i;
}
}
//3.切出左子树的中序
int[] leftInOrder = Arrays.copyOfRange(inorder, 0, leftSize + 1);
//切出左子树的后序
int[] leftPostOrder = Arrays.copyOfRange(postorder, 0, leftSize);
root.left = buildTree23(leftInOrder, leftPostOrder);
// 中序遍历 inorder = [9,3,15,20,7]
// 后序遍历 postorder = [9,15,7,20,3]
//4.切出右子树的中序
int[] rightInOrder = Arrays.copyOfRange(inorder, leftSize + 1, inorder.length);
//切出右子树的后序:copyOfRange()函数是对索引取左闭右开
int[] rightPostOrder = Arrays.copyOfRange(postorder, leftSize, postorder.length - 1);
root.right = buildTree23(rightInOrder, rightPostOrder);
return root;
}
判断一棵树是不是完全二叉树
/**
* @Description: 判断一棵树是不是完全二叉树
* solution:带着空节点层序遍历,如果遇到空节点之后的所有都是空节点--》完全二叉树
* 如果遇到空之后,又遇到飞空,不是完全二叉树
*/
public boolean isComplete(TreeNode root) {
if (root == null) {
return true;
}
LinkedList<TreeNode> queue = new LinkedList<>();
queue.addLast(root);
while (true) {
TreeNode front = queue.pollFirst();
if (front == null) {
//如果遇到空,就不走了,判断队列中残留的的是否全是空
break;
}
queue.addFirst(front.left);
queue.addFirst(front.right);
}
//循环走完了,判断空节点的后面是否还有非空
while (!queue.isEmpty()) {
TreeNode front = queue.pollFirst();
if (front != null) {
return false;
}
}
return true;
}
将一棵搜索树转换成双向链表
/**
* @Description: 输入一棵二叉搜索树(任意一个节点的左边比右边小),
* 将该二叉搜索树转换成一个排序的双向链表。
* 要求不能创建任何新的结点,只能调整树中结点指针的指向
* solution:中序是有序的
* 将节点串成双向链表:
* Node pre=null
* for(Node node:list){
* node.pre=pre;//node.left=pre;
* if(pre!=null){
* pre.next=node;//pre.right=node
* }
* pre=node;
* }
*/
private static TreeNode prev = null;
private static TreeNode head = null;
public TreeNode Convert(TreeNode pRootOfTree) {
prev = null;
head = null;
inOrderSereachTree(pRootOfTree);
return head;
}
public void inOrderSereachTree(TreeNode root) {
//1.中序遍历二叉树
//2.将中序遍历的节点穿成双向链表
if (root != null) {
inOrderSereachTree(root.left);
//处理根
buildLinkedList(root);
inOrderSereachTree(root.right);
}
}
private void buildLinkedList(TreeNode node) {
//搜索树的任何一个节点的左孩子小于右孩子
node.left = prev;
if (prev != null) {
prev.right = node;
} else {
head = node;
}
prev = node;
}
将二叉树转化为字符串
/**
* @Description: 你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
* 空节点则用一对空括号 "()" 表示。
* 省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对
* @Param:
* @return:
*/
public String tree2str(TreeNode t) {
if (t == null) {
return "";
}
StringBuilder sb = new StringBuilder();
//前序遍历得到节点,传入追加字符串,在第一次经过字符串时就记录下来
preOrder(t, sb);
sb.delete(0, 1);
sb.delete(sb.length() - 1, sb.length());
return sb.toString();
}
private void preOrder(TreeNode root, StringBuilder sb) {
if (root != null) {
sb.append("(");
//第一次经过节点时就记录下来
sb.append(root.val);
//如果左子树为空,右子树不为空记录值()
if (root.left == null && root.right != null) {
sb.append("()");
} else {
preOrder(root.left, sb);
}
preOrder(root.right, sb);
sb.append(")");
}
}
找到两棵子树最近的公共祖先
/**
* @Description:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
* “对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,
* 满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
* <p>
* 1.p或q至少有一个就是root,祖先是root
* 2.一个在root的左子树上,一个在右子树上,公共祖先是root
* 3.在一棵子树上,则递归到这颗子树上{
* 递归查找子树,如果在左子树上找到了p,右子树上找到了q,就是第一种情况(递归出口)
* * }
* @Param:
* @return:
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//保证节点不为空
if (root == p || root == q) {
return root;
}
boolean pInLeft = find(root.left, p);
boolean qInLeft = find(root.left, q);
/*
* 三种情况:1.分布在左右两个子树上--》root
* 2.根节点就是其中一个节点--》root
* 3.分布在同一个子树上(递归回12)
* */
if (pInLeft && qInLeft) {
//如果p在左子树上,q也在左子树上,递归查找
return lowestCommonAncestor(root.left, p, q);
}
if (!pInLeft && !qInLeft) {
//说明在右子树上
return lowestCommonAncestor(root.right, p, q);
}
//说明一个在左子树上 一个在右子树上,公共祖先为根
return root;
}
private boolean find(TreeNode root, TreeNode t) {
if (root == null) {
return false;
}
if (root == t) {
return true;
}
if (find(root.left, t)) {
return true;
}
return find(root.right, t);
}
通过层序遍历将二叉树装进容器
/**
* @Description: 层序遍历,将遍历的数据装入List<List<Integer>>容器
* solution:利用队列:一头进 一头出
* 1.启动 根入队列
* 2,取队首
* 2.拉下线(空节点不要)
*/
public List<List<Integer>> levelOrder(TreeNode root) {
//相当于一个二维数组,给顺序链表中放顺序链表
List<List<Integer>> list = new ArrayList<>();
if (root == null) {
return list;
}
class NodeLevel {
TreeNode node;
int level;
public NodeLevel(TreeNode node, int level) {
this.node = node;
this.level = level;
}
}
LinkedList<NodeLevel> queue = new LinkedList<>();
//队首入队,
queue.addLast(new NodeLevel(root, 0));
while (!queue.isEmpty()) {
//取队首
NodeLevel front = queue.pollFirst();
TreeNode node = front.node;
int level = front.level;
//list.size()随着遍历的层数的增加而增加
//如果是新层,则给元顺序的增加值,这个值是一个顺序链表
if (list.size() == level) {
//扩展为二维数组
list.add(new ArrayList<>());
}
//在当前层中对应的顺序链表中的顺序链表放值
list.get(level).add(node.val);
//拉下线,层数+1
if (node.left != null) {
queue.addLast(new NodeLevel(node.left, level + 1));
}
if (node.right != null) {
//拉下线,层数+1
queue.addLast(new NodeLevel(node.right, level + 1));
}
}
return list;
}