算法打卡day13|二叉树篇01|102.二叉树的层序遍历、226.翻转二叉树、101. 对称二叉树

在做题之前说明

offer()方法与offerLast()

Deque接口中的offer()方法与offerLast()方法都用于向双端队列的末尾添加元素,但它们之间有细微的差别。

offer()方法Queue接口中定义的 ,它被所有实现了Queue接口的类继承,包括Deque。当你调用offer()方法时,它会将元素添加到Deque的末尾。如果Deque已经满了offer()方法将抛出一个IllegalStateException 。而offerLast()方法是**Deque接口特有的,** 在Deque已满时不会抛出异常 ,而是返回一个特殊的值false ,表明元素没有被添加到队列中。这种行为使得offerLast()方法在某些情况下更加健壮,因为它避免了因队列满而导致的程序异常。

peek()peekFirst()

peek()方法是从**Queue接口继承来的** ,它返回队列头部的元素,但不移除它。如果队列为空,则peek()方法返回null

peekFirst()方法是**Deque接口特有的** ,它与peek()方法类似,也是返回队列头部的元素,但不移除它。然而,与peek()方法不同的是,peekFirst() 方法不会抛出空指针异常 ,即使队列为空。当队列为空时,peekFirst()方法返回null。这使得peekFirst()方法在某些情况下更加安全和可靠

以此类推,其他的比如poll()和pollFirst()也是如此;

算法题

Leetcode 102.二叉树的层序遍历

题目链接:102.二叉树的层序遍历

大佬视频讲解:二叉树的层序遍历视频讲解

个人思路

层序遍历也就是图论中的广度优先遍历,是使用队列的结构;用队列一层层遍历,并加入结果数组,最后返回;

解法
迭代法
java 复制代码
class Solution {
    public List<List<Integer>> resList = new ArrayList<List<Integer>>();

    public List<List<Integer>> levelOrder(TreeNode root) {
        checkFun01(root);

        return resList;
    }

    public void checkFun01(TreeNode root){
        if(root==null) return;

        Queue<TreeNode> que=new LinkedList<TreeNode>();
        que.offer(root);//加入节点

        while(!que.isEmpty()){//终止条件

            int len =que.size();//当前层数 元素的数量
            List<Integer> itemList=new ArrayList<Integer>();

            while(len>0){
                TreeNode temp=que.poll();
                itemList.add(temp.val);//结果子列表加入值

                if(temp.left!=null) que.offer(temp.left);//加入左节点
                if(temp.right!=null) que.offer(temp.right);

                len--;//遍历下一个节点
            }
            resList.add(itemList);//结果列表加入子列表
        }
    }

}

时间复杂度:O( n**)**;(遍历整棵树)

空间复杂度:O( n**);**(使用一个结果子列表,和一个列表)

递归法
java 复制代码
class Solution {
    //1.确定递归函数的参数和返回值
    public List<List<Integer>> resList = new ArrayList<List<Integer>>();


    public List<List<Integer>> levelOrder(TreeNode root) {
        checkFun02(root,0);

        return resList;
    }


    
    public void checkFun02(TreeNode root, int deep){
        if(root==null) return;//2.确定递归终止条件
        
        //3.确定单层递归的逻辑
        deep++;//层级
        if(resList.size()<deep){//利用list的索引值进行层级界定

            List<Integer> item=new ArrayList<Integer>();
            resList.add(item); //当层级增加时,list的Item也增加
        }
        resList.get(deep-1).add(root.val);//get 层级 

        checkFun02(root.left,deep);//递归左子树
        checkFun02(root.right,deep);//递归右子树
        
    }
}

时间复杂度:O( n**)**;(遍历整棵树)

空间复杂度:O( n**);**(使用一个结果子列表,和一个列表)


Leetcode226.翻转二叉树

题目链接:226.翻转二叉树

大佬视频讲解:翻转二叉树视频讲解

个人思路

遍历二叉树,将每个节点的左右孩子交换一下

解法

这道题关键在于遍历顺序,这道题目使用前序遍历,后序遍历和层序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次

递归法(DFS)
java 复制代码
class Solution {
    public TreeNode invertTree(TreeNode root) {//1.确定递归函数的参数和返回值
        if (root == null) {//2.确定终止条件
            return null;
        }
        
        //3.确定单层递归的逻辑
        invertTree(root.left);//后序遍历:左右中(根)
        invertTree(root.right);
        swapChildren(root);
        return root;
    }

    private void swapChildren(TreeNode root) {
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
    }
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(n);(使用临时节点来换位)

迭代法(BFS)
java 复制代码
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {return null;}

        ArrayDeque<TreeNode> deque = new ArrayDeque<>();//队列进行层序遍历
        deque.offer(root);

        while (!deque.isEmpty()) {
            int size = deque.size();
            while (size-- > 0) {//遍历各层的各个节点
                TreeNode node = deque.poll();
                swap(node);//交换节点的左右子树

                if (node.left != null) deque.offer(node.left);
                if (node.right != null) deque.offer(node.right);
            }
        }
        return root;
    }

    public void swap(TreeNode root) {
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
    }
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(n);(使用队列进行层序遍历和临时节点来换位)


Leetcode101. 对称二叉树

题目链接:101. 对称二叉树

大佬视频讲解:对称二叉树视频讲解

个人思路

将二叉树分成两半一边为左子树A,一边为右子树B,然后就对比 A节点的左边和B节点的右边,A节点的右边和B节点的左边,都相等就对称了

解法
递归法

因为要遍历两棵树而且要比较内侧和外侧节点 ,所以一个树的遍历顺序是左右中 ,一个树的遍历顺序是右左中

递归三部曲

1.确定递归函数的参数和返回值

因为要比较的是根节点的两个子树是否是相互翻转的,参数就是左子树节点和右子树节点。返回值为布尔类型。

2.确定终止条件

要比较两个节点数值相不相同,要把两个节点为空的情况分清楚,不然后面比较数值的时候就会操作空指针了。

节点为空的情况有:

  1. 1.左节点为空,右节点不为空,不对称,return false
  2. 左不为空,右为空,不对称 return false
  3. 左右都为空,对称,返回true

此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:左右都不为空,比较节点数值,不相同就return false

把以上情况都排除之后,剩下的就是 左右节点都不为空,且数值相同的情况

3.确定单层递归的逻辑

处理 左右节点都不为空,且数值相同的情况。

1.比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。

2.比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。

如果左右都对称就返回true ,有一侧不对称就返回false 。

java 复制代码
 public boolean isSymmetric1(TreeNode root) {
        return compare(root.left, root.right);
    }

    private boolean compare(TreeNode left, TreeNode right) {1.确定递归函数的参数和返回值
        
        2.确定终止条件
        //处理节点为空的4种情况
        if (left == null && right != null) {
            return false;
}
        if (left != null && right == null) {
            return false;
        }

        if (left == null && right == null) {
            return true;
        }
        if (left.val != right.val) {
            return false;
        }

        3.确定单层递归的逻辑
        // 递归比较二叉树外侧
        boolean compareOutside = compare(left.left, right.right);
        // 递归比较内侧
        boolean compareInside = compare(left.right, right.left);
        return compareOutside && compareInside;//都为真则为真
    }

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(1);(无使用额外空间)

迭代法
java 复制代码
    public boolean isSymmetric3(TreeNode root) {
        Queue<TreeNode> deque = new LinkedList<>();
        deque.offer(root.left);
        deque.offer(root.right);

        while (!deque.isEmpty()) {
            TreeNode leftNode = deque.poll();
            TreeNode rightNode = deque.poll();
            if (leftNode == null && rightNode == null) {
                continue;
            }

            // 将其他三个判断条件合并
            if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
                return false;
            }
            //左子树的左节点和右子树的右节点
            deque.offer(leftNode.left);
            deque.offer(rightNode.right);

            //左子树的右节点和右子树的左节点
            deque.offer(leftNode.right);
            deque.offer(rightNode.left);
        }
        return true;
    }

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(使用队列)

以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网代码随想录算法官网代码随想录算法官网

相关推荐
浮生如梦_35 分钟前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei2 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师2 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
师太,答应老衲吧3 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Yaml43 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~4 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端