IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【数据结构】——二叉树oj题详解 -> 正文阅读

[数据结构与算法]【数据结构】——二叉树oj题详解

目录

1、100. 相同的树 - 力扣(LeetCode)

2、572. 另一棵树的子树 - 力扣(LeetCode)

3、110. 平衡二叉树 - 力扣(LeetCode)

4、101. 对称二叉树 - 力扣(LeetCode)

5、102. 二叉树的层序遍历 - 力扣(LeetCode)

?6、判断该树是否为完全二叉树

七、二叉树遍历_牛客题霸_牛客网 (nowcoder.com)

?八、236. 二叉树的最近公共祖先 - 力扣(LeetCode)

九、二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com)

十、105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

十一、106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

十二、非递归实现二叉树的前中后序遍历


1、100. 相同的树 - 力扣(LeetCode)

?我们考虑它相同和不相同的情况,再用递归遍历:

完整代码:

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);
    }

2、572. 另一棵树的子树 - 力扣(LeetCode)

这道题,我们可以直接用上一道题的代码,其思路如下:

  1. 我们首先判断root和subRoot是不是两颗相同的树,是的话就返回true?
  2. 不是的话,就继续判断subRoot是不是root.left的左子树的子树或者root.left是不是和和subRoot为相同的树
  3. 同理再判断subRoot和root.right;

完整代码:

class Solution {
    //时间复杂度为:n * m
    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 || subRoot == null){
            return false;
        }
        if (isSameTree(root,subRoot)){
            return true;
        }
        if(isSubtree(root.left,subRoot)){
            return true;
        }
        if(isSubtree(root.right,subRoot)){
            return true;
        }
        return false;
    }
}

3、110. 平衡二叉树 - 力扣(LeetCode)

思路:

  1. ?首先这道题判断平衡也就是左右子树的高度差,那就需要求出左右子树的高度,,进行比较
  2. 然后还需要求出左子树的子树的高度差,和右子树的子树的高度差,来判断左子树和右子树是否平衡。
  3. 所以需要遍历树的每一个结点

完整代码:

class Solution {
    //时间复杂度为:n * n
    int getHeight(TreeNode root){
        if (root == null){
            return 0;
        }
        int leftTree = getHeight(root.left);
        int rightTree = getHeight(root.right);
        return leftTree > rightTree ? leftTree+1 : rightTree+1;
    }
    public boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        return Math.abs(leftHeight-rightHeight) <= 1 
        && isBalanced(root.left)
        && isBalanced(root.right);
    }
}

?上面的这种解法的时间复杂度是O(n^2),会出现大量的的重复计算,当计算根结点的左子树高度时,递归到数字九时返回一个2就已经说明了该树不平衡,所以我们从下向上计算高度时顺便判断一下,这样的话时间复杂度就是O(n)

class Solution {
    int getHeight(TreeNode root){
        if (root == null){
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        if(leftHeight >= 0 && rightHeight >= 0 && Math.abs(leftHeight - rightHeight) <= 1){
            return Math.max(leftHeight,rightHeight) + 1;
        }else{
            //返回-1 就说明已经出现了不平衡
            return -1;
        }
    }
    public boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }
        return getHeight(root) >= 0;
    }
}

4、101. 对称二叉树 - 力扣(LeetCode)

?思路就是判断root的左右子树是否对称:左子树的右树和右子树的左树是否相同:

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null) {
            return true;
        }
        return isSymmetricChild(root.left,root.right);
    }
    private boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
        //判断左子树的右树和右子树的左树是否相同.
        if (leftTree == null && rightTree != null || leftTree != null && rightTree == null){
            return false;
        }
        //是否都为空
        if (leftTree == null && rightTree == null){
            return true;
        }
        //判断val值
        if (leftTree.val != rightTree.val){
            return false;
        }
        //进行递归左子树的右树和右子树的左树
        return isSymmetricChild(leftTree.left, rightTree.right) &&
                isSymmetricChild(leftTree.right, rightTree.left);
    }
}

5、102. 二叉树的层序遍历 - 力扣(LeetCode)

思路:

  1. 首先要创建两个顺序表来分层存储二叉树
  2. 创建一个队列,先把根结点入对,再把top弹出的同时并赋值给cur并打印
  3. 并且把top的左右子树入队,直到树为空

?完整代码:

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ret = new ArrayList<List<Integer>>();
        if(root == null){
            return ret;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while(!queue.isEmpty()){
            List<Integer> leve = new ArrayList<Integer>();
            int queue_size = queue.size();
            for(int i = 0; i < queue_size; i++){
                TreeNode node = queue.poll();
                leve.add(node.val);
                if(node.left != null){
                    queue.offer(node.left);
                }
                if(node.right != null){
                    queue.offer(node.right);
                }
            }
            ret.add(leve);
        }
        return ret;
    }
}

?6、判断该树是否为完全二叉树

思路:

  1. 将null也入队,如果队列中只剩下null,说明就为完全二叉树
  2. 当非完全二叉树入队时,出队的时候会发现队列中还剩下null和结点

?

?完整代码:

boolean isCompleteTree(TreeNode root){
        if (root == null){
            return true;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            TreeNode cur = queue.poll();
            if (cur != null){
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else {
                break;
            }
        }
        while (!queue.isEmpty()){
            TreeNode cur = queue.peek();
            if (cur != null){
                //不是完全二叉树
                return false;
            }else {
                queue.poll();
            }
        }
        return true;
    }

七、二叉树遍历_牛客题霸_牛客网 (nowcoder.com)

import java.util.*;

public class Main {
    class TreeNode{
        public char val;
        public TreeNode left;
        public TreeNode right;
        public TreeNode(char val){
            this.val = val;
        }
    }
    public int i = 0;
    //创建树
    public  TreeNode createTree(String s){
        TreeNode root = null;
        if (s.charAt(i) != '#'){
            root = new TreeNode(s.charAt(i));
            i++;
            root.left = createTree(s);
            root.right = createTree(s);
        }else {
            i++;
        }
        return root;
    }
    public 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 scanner = new Scanner(System.in);
        while (scanner.hasNextLine()){
            String s = scanner.nextLine();
            Main m = new Main();
            TreeNode root = m.createTree(s);
            m.inorder(root);
        }
    }
}

?八、236. 二叉树的最近公共祖先 - 力扣(LeetCode)

?列出求公共祖先会出现的情况:

分析:

  1. 假设这是一颗二叉搜索树(中序遍历是有序的),p == root?|| q == root,?此时公共祖先就是root
  2. 当p和q刚好在左右子树中,公共祖先就是根结点
  3. 当p.val和q.val都小于root.val,此时p和q都在root的左子树中,此时就在左子树中找,右子树同理;

完整代码:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
        if(root == null){
            return null;
        }
        if(root == p || root == q){
            return root;
        }
        TreeNode retleft = lowestCommonAncestor(root.left,p,q);
        TreeNode retright = lowestCommonAncestor(root.right,p,q);
        if(retleft != null && retright != null){
            return root;
        }else if(retleft != null){//都在左树
            return retleft;
        }else{
            return retright;
        }
    }
}

当我们用栈的思想来解决这道题时,可以有:

?完整代码:

class Solution {
     //找到根结点到指定节点node之间路径上的所有结点,存储到栈中
     private boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack) {
        if (root == null || node == null) {
            return false;
        }
        stack.push(root);
        if (root == node) {
            return true;
        }
        boolean ret1 = getPath(root.left, node, stack);
        if (ret1) {
            return true;
        }
        boolean ret2 = getPath(root.right, node, stack);
        if (ret2) {
            return true;
        }
        //当前根结点不是,根的左右子树都不是
        stack.pop();
        return false;
    }

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
        Stack<TreeNode> stack1 = new Stack<>();
        getPath(root,p,stack1);
        Stack<TreeNode> stack2 = new Stack<>();
        getPath(root,q,stack2);
        int size1 = stack1.size();
        int size2 = stack2.size();
        if(size1 > size2){
            int tmp = size1 - size2;
            while(tmp != 0){
                stack1.pop();
                tmp--;
            }
        }else{
            int tmp = size2 - size1;
            while(tmp != 0){
                stack2.pop();
                tmp--;
            }
        }
        while(!stack1.empty() && !stack2.empty()){
            if(stack1.peek()  == stack2.peek()){
                return stack1.peek();
            }else{
                stack1.pop();
                stack2.pop();
            }
        }
        return null;
    }
}

九、二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com)

思路:

  1. 题目要求转换成一个排序的双向链表,并且是一颗二叉搜索树,所以我们要使用中序遍历,遍历树
  2. 然后利用每个节点的left和right作为前驱后继进行连接?

?

public class Solution {
    TreeNode prev = null;
    public void ConvertChild(TreeNode root){
        if (root == null){
            return;
        }
        ConvertChild(root.left);
        root.left = prev;
        if (prev != null){
            prev.right = root;
        }
        prev = root;
        ConvertChild(root.right);
    }
    public TreeNode Convert(TreeNode pRootOfTree){
        if (pRootOfTree == null){
            return null;
        }
        ConvertChild(pRootOfTree);
        TreeNode head = pRootOfTree;
        while(head.left != null){
            head = head.left;
        }
        return head;
    }
}

十、105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

思路:

?完整代码:

class Solution {
    public int preIndex = 0;
    public TreeNode buildTreeChild(int[] preorder, int[] inorder,int inBegin,int inEnd){
        if(inBegin > inEnd){
            return null;
        }
        TreeNode root = new TreeNode(preorder[preIndex]);
        int rootIndex = findInorderIndex(inorder,preorder[preIndex],inBegin,inEnd);
        preIndex++;
        root.left = buildTreeChild(preorder,inorder, inBegin, rootIndex-1);
        root.right = buildTreeChild(preorder,inorder,rootIndex+1, inEnd);
        return root;
    }
    //找到根结点的位置
    private int findInorderIndex(int[] inorder,int val,int inBegin,int inEnd){
        for(int i = inBegin; i <= inEnd; i++){
            if(inorder[i] == val){
                return i;
            }
        }
        return -1;
    }
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTreeChild(preorder,inorder,0,inorder.length-1);
    }
}

同理这道题也是一样的道理:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

只不过变成了后序序列倒着是根结点

class Solution {
    public int postIndex;
    public TreeNode buildTreeChild(int[] postorder, int[] inorder,int inBegin,int inEnd){
        if(inBegin > inEnd){
            return null;
        }
        TreeNode root = new TreeNode(postorder[postIndex]);
        int rootIndex = findInorderIndex(inorder,postorder[postIndex],inBegin,inEnd);
        postIndex--;
        root.right = buildTreeChild(postorder,inorder,rootIndex+1, inEnd);
        root.left = buildTreeChild(postorder,inorder, inBegin, rootIndex-1);

        return root;
    }
    private int findInorderIndex(int[] inorder,int val,int inBegin,int inEnd){
        for(int i = inBegin; i <= inEnd; i++){
            if(inorder[i] == val){
                return i;
            }
        }
        return -1;
    }
    public TreeNode buildTree(int[] inorder,int[] postorder) {
        postIndex = postorder.length-1;
        return buildTreeChild(postorder,inorder,0,inorder.length-1);
    }
}

十一、106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

?

?思路:

每颗小子树走完都会加一个右括号,当然除了根结点剩下的结点都先加一个左括号,变美丽树,并将其打印出来:

class Solution {
    public String tree2str(TreeNode root) {
        //通过StringBuilder修改字符串
        StringBuilder sb = new StringBuilder();
        tree2strChild(root,sb);
        return sb.toString();
    }
    private void tree2strChild(TreeNode t,StringBuilder sb){
        if(t == null){
            return;
        }
        sb.append(t.val);
        //左子树不为空就加个左括号
        if(t.left != null){
            sb.append("(");
            tree2strChild(t.left,sb);
            sb.append(")");
        }else{
            if(t.right == null){
                return;
            }else{
                sb.append("()");
            }
        }
        if(t.right == null){
            return;
        }else{
            sb.append("(");
            tree2strChild(t.right,sb);
            sb.append(")");
        }
    }
}

十二、非递归实现二叉树的前中后序遍

前序遍历思路:

创建一个栈,将根结点入栈并打印,再遍历root.left,当结点左右子树为空时就出栈并赋值给top记录下来,再继续遍历root.right:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root){
        List<Integer> ret = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                System.out.println(cur.val + " ");
                ret.add(cur.val);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            cur = top.right;
        }
        return ret;
    }
}

中序遍历同理:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            System.out.println(cur.val + " ");
            list.add(top.val);
            cur = top.right;
        }
        return list;
    }
}

后序遍历:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode prev = null;
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            //不能直接弹出
            TreeNode top = stack.peek();
            
            if(top.right == null || top.right == prev){
                stack.pop();
                list.add(top.val);
                prev = top;
            }else{
                cur = top.right;
            }
        }
        return list;
    }
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 01:36:44  更:2022-09-04 01:38:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:49:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码