🎉🎉🎉写在前面: 博主主页:🌹🌹🌹戳一戳,欢迎大佬指点! 博主秋秋:QQ:1477649017 欢迎志同道合的朋友一起加油喔💪 目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个小菜鸟嘿嘿 -----------------------------谢谢你这么帅气美丽还给我点赞!比个心-----------------------------
一,有关二叉树性质的证明
二,实题解析
三,二叉树相关oj题
🌟检查两棵树是否相同
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p != null && q == null || p == null && q != null){
return false;
}
if(p == null && q == null){
return true;
}
if(p.val != q.val){
return false;
}
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
}
判断一下这题的时间复杂度为:O(min(m,n)),其中m是左边的树的节点个数,n是右边的树的节点个数,因为我们这里的最坏情况肯定是要把小的那棵树遍历完,而不是看大的树,小的树遍历完了不相同那就直接不用比较了。
🌟另一棵树的子树
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p != null && q == null || p == null && q != null){
return false;
}
if(p == null && q == null){
return true;
}
if(p.val != q.val){
return false;
}
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null){
return false;
}
if(isSameTree(root,subRoot)){
return true;
}
return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot);
}
}
时间复杂度分析,假设root树有m个节点,subRoot树有n个节点,因为是每次递归进去判断是不是子树,那对于每次是不是子树的判断,就是看两个树是不是相同,这个过程也是一个递归。所以最坏的情况就是subRoot和root的每一个节点都判断一下是不是子树,假设root树是n个节点,subRoot树是m个节点,那最坏就是要判断n*m次,所以时间复杂度就是O(n x m)。
🌟二叉树的最大深度
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
}
}
时间复杂度:O(n)
🌟判断一棵二叉树是不是平衡二叉树
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
}
public boolean isBalanced(TreeNode root) {
if(root == null){
return true;
}
int leftHeight = maxDepth(root.left);
int rightHeight = maxDepth(root.right);
if(Math.abs(leftHeight - rightHeight) > 1){
return false;
}else{
return isBalanced(root.left) && isBalanced(root.right);
}
}
}
时间复杂度:O(n^2),这里也是一个嵌套的递归,isBalanced()是递归到二叉树的每一个节点,然后判断该节点是否平衡,又是要递归求左右子树的高度,所以又相当于遍历了一遍二叉树。中间存在很多的重复计算,你在计算3这个节点的左树高度时,遍历了左树,在判断9这个节点的时候,又会重复遍历到很多的节点。所以,这个方法的时间复杂度比较高,面试要求的话肯定是达不到的。
【解法优化:】
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
int leftHeight = maxDepth(root.left);
int rightHeight = maxDepth(root.right);
if(leftHeight >= 0 && rightHeight >= 0 && Math.abs(leftHeight - rightHeight) <=1){
return (Math.max(leftHeight,rightHeight)) + 1;
}else{
return -1;
}
}
public boolean isBalanced(TreeNode root) {
if(root == null){
return true;
}
return maxDepth(root) > 0;
}
}
优化之后就只走了一个递归函数。因为其实对于根节点而言,你判断它是否平衡的时候,就已经把所有的节点都要遍历完,这个过程中就可能会出现不平衡的情况,这个时候这棵树已经就是不平衡的了,没必要再递归判断左子树右子树的节点了。现在的时间复杂度就降到了O(n)。
🌟判断一棵二叉树是否对称
class Solution {
public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree){
if(leftTree != null && rightTree == null || leftTree == null && rightTree != null){
return false;
}
if(leftTree == null && rightTree == null){
return true;
}
if(leftTree.val != rightTree.val ){
return false;
}
return isSymmetricChild(leftTree.left,rightTree.right) && isSymmetricChild(leftTree.right,rightTree.left);
}
public boolean isSymmetric(TreeNode root) {
if(root == null){
return true;
}
return isSymmetricChild(root.left,root.right);
}
}
🌟二叉树的分层遍历
【前导:】
void levelOrder(TreeNode root){
if(root == null){
return;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode cur = queue.poll();
System.out.print(cur.val + " ");
if(cur.leftChild != null){
queue.offer(cur.leftChild);
}
if(cur.rightChild != null){
queue.offer(cur.rightChild);
}
}
}
层序遍历的过程得用到队列,因为队列是先进先出,符合我们层序遇到节点就打印的特点。首先把根节点入队,然后只要队列不为空就出队队头元素,出对的同时会把这个元素的左孩子,右孩子入队,就这样一直循环下去,最终的打印结果就是层序的结果。
那么下面的分层遍历,只不过是要我们把每一层都区分开。那我们只要在每次出队之前看一下队列中的元素个数,那就是这一层的个数,并且保证每次出的时候都把这一层出完,然后每层元素都会被加入到ArrayList中,这样就被区分开了。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<>();
if(root == null){
return ret;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
List<Integer> list = new ArrayList<>();
while(size != 0){
TreeNode cur = queue.poll();
size--;
if(cur.left != null){
queue.offer(cur.left);
}
if(cur.right != null){
queue.offer(cur.right);
}
list.add(cur.val);
}
ret.add(list);
}
return ret;
}
}
分层遍历的题记住就是用队列解,比如之前阿里考过的题,求一棵树的左视图,右视图,其实就只是上面这个题,ret这个ArrayList每一个元素的第一个元素组合起来就是左视图,最后一个元素组合起来就是右视图。
🌟二叉树的构建和遍历
import java.util.Scanner;
class TreeNode{
public char val;
public TreeNode left;
public TreeNode right;
public TreeNode(char val){
this.val = val;
}
}
public class Main{
public static int i = 0;
public static TreeNode creatTree(String s){
TreeNode root = null;
if(s.charAt(i) != '#'){
root = new TreeNode(s.charAt(i));
i++;
root.left = creatTree(s);
root.right = creatTree(s);
}else{
i++;
}
return root;
}
public static void inOrder(TreeNode root){
if(root == null){
return ;
}
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
public static void main(String args[]){
Scanner scan = new Scanner(System.in);
while(scan.hasNextLine()){
String s = scan.nextLine();
TreeNode root = creatTree(s);
inOrder(root);
}
}
}
它给你的字符串是前序遍历出来的字符串顺序,所以我们就按照它的那个顺序递归创建就行。如果当前字符不是#,那就先把该节点创建,然后去递归创建其左子树,然后再是右子树。我们把每个节点串起来的过程就是你返回节点的过程。
🌟求二叉树指定节点的公共祖先
【解法一:】
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return null;
}
if(p == root || q == root){
return root;
}
TreeNode leftFind = lowestCommonAncestor(root.left,p,q);
TreeNode rightFind = lowestCommonAncestor(root.right,p,q);
if(leftFind !=null && rightFind != null){
return root;
}else if(leftFind != null){
return leftFind;
}else{
return rightFind;
}
}
}
这里只是以二叉搜索树为例,其中值的比较在本题是不需要的,因为题目要求的就只是二叉树就行,但是p,q可能存在的情况就是如上。所以我们就先判断p,q是不是在root处,然后再去左边找,再去右边找,然后看两个返回值的情况。
【解法二:】
class Solution {
public boolean getPath(TreeNode root,TreeNode findNode,Stack<TreeNode> stack){
if(root == null){
return false;
}
stack.push(root);
if(root == findNode){
return true;
}
boolean ret1 = getPath(root.left,findNode,stack);
if(ret1){
return true;
}
boolean ret2 = getPath(root.right,findNode,stack);
if(ret2){
return true;
}
stack.pop();
return false;
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return null;
}
Stack<TreeNode> stackP = new Stack<>();
Stack<TreeNode> stackQ = new Stack<>();
boolean ret1 = getPath(root,p,stackP);
boolean ret2 = getPath(root,q,stackQ);
if(ret1 == true && ret2 == true){
if(stackP.size() > stackQ.size()){
int len = stackP.size() - stackQ.size();
while(len != 0){
stackP.pop();
len--;
}
}else{
int len = stackQ.size() - stackP.size();
while(len != 0){
stackQ.pop();
len--;
}
}
}
while(!stackP.isEmpty() && !stackQ.isEmpty()){
if(stackP.peek() == stackQ.peek()){
return stackP.peek();
}
stackP.pop();
stackQ.pop();
}
return null;
}
}
🌟二叉树转换成双向链表
import java.util.*;
public class Solution {
public TreeNode prev = null;
public void inOrder(TreeNode root){
if(root == null){
return ;
}
inOrder(root.left);
root.left = prev;
if(prev != null){
prev.right = root;
}
prev = root;
inOrder(root.right);
}
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null){
return null;
}
inOrder(pRootOfTree);
TreeNode head = pRootOfTree;
while(head.left != null){
head = head.left;
}
return head;
}
}
🌟根据二叉树的前序中序遍历构建二叉树
class Solution {
public int preIndex = 0;
private TreeNode buildChildTree(int[] preorder, int[] inorder,int begin,int end){
if(begin > end){
return null;
}
TreeNode root = new TreeNode(preorder[preIndex]);
int fIndex = findIndex(inorder,preorder[preIndex],begin,end);
preIndex++;
root.left = buildChildTree(preorder,inorder,begin,fIndex - 1);
root.right = buildChildTree(preorder,inorder,fIndex + 1,end);
return root;
}
private int findIndex(int[] inorder,int findNum,int begin,int end){
for(int i = begin;i <= end;i++){
if(inorder[i] == findNum){
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildChildTree(preorder,inorder,0,inorder.length - 1);
}
}
🌟根据二叉树的中序后序遍历构建二叉树
class Solution {
public int postIndex;
private TreeNode buildChildTree(int[] postorder, int[] inorder,int begin,int end){
if(begin > end){
return null;
}
TreeNode root = new TreeNode(postorder[postIndex]);
int fIndex = findIndex(inorder,postorder[postIndex],begin,end);
postIndex--;
root.right = buildChildTree(postorder,inorder,fIndex + 1,end);
root.left = buildChildTree(postorder,inorder,begin,fIndex - 1);
return root;
}
private int findIndex(int[] inorder,int findNum,int begin,int end){
for(int i = begin;i <= end;i++){
if(inorder[i] == findNum){
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
postIndex = postorder.length - 1;
return buildChildTree(postorder,inorder,0,inorder.length - 1);
}
}
原理和上面前序中序构建是一样的,只不过后序遍历的数组我们遍历的时候是从后往前,在构建子树的时候我们也是先构建右树再构建左树。
🌟二叉树创建字符串
class Solution {
public String tree2str(TreeNode root) {
if(root == null){
return null;
}
StringBuilder stringBuilder = new StringBuilder();
tree2strChild(root,stringBuilder);
return stringBuilder.toString();
}
private void tree2strChild(TreeNode t,StringBuilder stringBuilder){
if(t == null){
return ;
}
stringBuilder.append(t.val);
if(t.left != null){
stringBuilder.append("(");
tree2strChild(t.left,stringBuilder);
stringBuilder.append(")");
}else{
if(t.right != null){
stringBuilder.append("()");
}else{
return;
}
}
if(t.right != null){
stringBuilder.append("(");
tree2strChild(t.right,stringBuilder);
stringBuilder.append(")");
}else{
return ;
}
}
}
🌟二叉树的前序遍历非递归实现
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
TreeNode cur = root;
while(cur != null || !stack.empty()){
while(cur != null){
stack.push(cur);
list.add(cur.val);
cur = cur.left;
}
TreeNode top = stack.pop();
cur = top.right;
}
return list;
}
}
🌟二叉树的中序遍历非递归实现
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
TreeNode cur = root;
while(cur != null || !stack.empty()){
while(cur != null){
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.pop();
list.add(top.val);
cur = top.right;
}
return list;
}
}
🌟二叉树的后序遍历非递归实现
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
TreeNode cur = root;
TreeNode pre = null;
while(cur != null || !stack.empty()){
while(cur != null){
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.peek();
if(top.right == null || top.right == pre){
stack.pop();
list.add(top.val);
pre = top;
}else{
cur = top.right;
}
}
return list;
}
}
今天关于二叉树的分享就到这了,后面会陆陆续续的恢复更新了的,大家持续关注哟,如果觉得写的不错的话还请点点赞咯,十分感谢呢!🥰🥰🥰
|