算法打卡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);(使用队列)

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

相关推荐
XiaoLeisj26 分钟前
【递归,搜索与回溯算法 & 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(二)
数据结构·算法·leetcode·决策树·深度优先·剪枝
禁默38 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Jasmine_llq1 小时前
《 火星人 》
算法·青少年编程·c#
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb42152871 小时前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶1 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
闻缺陷则喜何志丹1 小时前
【C++动态规划 图论】3243. 新增道路查询后的最短距离 I|1567
c++·算法·动态规划·力扣·图论·最短路·路径