【每日算法】一题双解 :「树的遍历」&「递归」 |Python 主题月

简介: 【每日算法】一题双解 :「树的遍历」&「递归」 |Python 主题月

网络异常,图片无法展示
|


题目描述



这是 LeetCode 上的 671. 二叉树中第二小的节点 ,难度为 简单


Tag : 「二叉树」、「树的遍历」、「递归」


给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。


更正式地说,root.val = min(root.left.val, root.right.val) 总成立。


给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。


 

示例 1:

网络异常,图片无法展示
|


输入:root = [2,2,5,null,null,5,7]
输出:5
解释:最小的值是 2 ,第二小的值是 5 。
复制代码


示例 2:

网络异常,图片无法展示
|


输入:root = [2,2,2]
输出:-1
解释:最小的值是 2, 但是不存在第二小的值。
复制代码


提示:


  • 树中节点数目在范围 [1, 25][1,25]
  • 11 <= Node.val <= 2^{31}231 - 1
  • 对于树中每个节点 root.val == min(root.left.val, root.right.val)


树的遍历



一个朴素的做法是,直接对树进行遍历(广度 & 深度),使用 HashSet 进行存储,得到所有去重后的节点大小。


然后找次小值的方式有多种:可以通过排序找次小值,复杂度为 O(n\log{n})O(nlogn);也可以使用经典的两个变量 & 一次遍历的方式,找到次小值,复杂度为 O(n)O(n)


Java 代码:


class Solution {
    Set<Integer> set = new HashSet<>();
    public int findSecondMinimumValue(TreeNode root) {
        dfs(root);
        if (set.size() < 2) return -1;
        int first = Integer.MAX_VALUE, second = Integer.MAX_VALUE;
        for (int i : set) {
            if (i <= first) {
                second = first;
                first = i;
            } else if (i <= second) {
                second = i;
            }
        }
        return second;
    }
    void dfs(TreeNode root) {
        if (root == null) return;
        set.add(root.val);
        dfs(root.left);
        dfs(root.right);
    }
}
复制代码


class Solution {
    Set<Integer> set = new HashSet<>();
    public int findSecondMinimumValue(TreeNode root) {
        bfs(root);
        if (set.size() < 2) return -1;
        int first = Integer.MAX_VALUE, second = Integer.MAX_VALUE;
        for (int i : set) {
            if (i <= first) {
                second = first;
                first = i;
            } else if (i <= second) {
                second = i;
            }
        }
        return second;
    }
    void bfs(TreeNode root) {
        Deque<TreeNode> d = new ArrayDeque<>();
        d.addLast(root);
        while (!d.isEmpty()) {
            TreeNode poll = d.pollFirst();
            set.add(poll.val);
            if (poll.left != null) d.addLast(poll.left);
            if (poll.right != null) d.addLast(poll.right);
        }
    }
}
复制代码


Python 3 代码:


class Solution:
    hashset = set()
    def findSecondMinimumValue(self, root: TreeNode) -> int:
        self.hashset = set()
        self.dfs(root)
        if len(self.hashset) < 2:
            return -1
        first = second = inf
        for i in self.hashset:
            if i <= first:
                second = first
                first = i
            elif i <= second:
                second = i
        return second
    def dfs(self, root):
        if not root:
            return
        self.hashset.add(root.val)
        self.dfs(root.left)
        self.dfs(root.right)
复制代码


class Solution:
    hashset = set()
    def findSecondMinimumValue(self, root: TreeNode) -> int:
        self.hashset = set()
        self.bfs(root)
        if len(self.hashset) < 2:
            return -1
        first = second = inf
        for i in self.hashset:
            if i <= first:
                second = first
                first = i
            elif i <= second:
                second = i
        return second
    def bfs(self, root):
        d = deque([root])
        while d:
            poll = d.popleft()
            self.hashset.add(poll.val)
            if poll.left:
                d.append(poll.left)
                d.append(poll.right)
复制代码


  • 时间复杂度:树的搜索复杂度为 O(n)O(n),通过线性遍历找次小值,复杂度为 O(n)O(n)。整体复杂度为 O(n)O(n)
  • 空间复杂度:O(n)O(n)


递归



解法一显然没有利用到本题核心条件 :「root.val = min(root.left.val, root.right.val)」和「每个子节点数量要么是 0 要么是 2」。


我们可以设计如下递归函数,含义为 root 为根的树进行搜索,找到值比 cur 大的最小数。然后使用全局变量 ans 存储答案。


void dfs(TreeNode root, int cur)
复制代码


那么最终搜索范围为 dfs(root, root.val),这是因为 性质 root.val = min(root.left.val, root.right.val),即最小值会不断往上传递,最终根节点必然是全局最小值


然后再结合「每个子节点数量要么是 0 要么是 2」,我们可以特判一下 ans 是否为第一次赋值,如果给 ans 赋了新值或者更新了更小的 ans,则不再需要往下搜索了。


Java 代码:


class Solution {
    int ans = -1;
    public int findSecondMinimumValue(TreeNode root) {
        dfs(root, root.val);
        return ans;
    }
    void dfs(TreeNode root, int cur) {
        if (root == null) return ;
        if (root.val != cur) {
            if (ans == -1) ans = root.val;
            else ans = Math.min(ans, root.val);
            return ;
        }
        dfs(root.left, cur);
        dfs(root.right, cur);
    }
}
复制代码


Python 3 代码:


class Solution:
    ans = -1
    def findSecondMinimumValue(self, root: TreeNode) -> int:
        self.ans = -1
        self.dfs(root, root.val)
        return self.ans
    def dfs(self, root, cur):
        if not root:
            return
        if root.val != cur:
            if self.ans == -1:
                self.ans = root.val
            else:
                self.ans = min(self.ans, root.val)
            return
        self.dfs(root.left, cur)
        self.dfs(root.right, cur)
复制代码


  • 时间复杂度:O(n)O(n)
  • 空间复杂度:忽略递归带来的空间开销。复杂度为 O(1)O(1)


最后



这是我们「刷穿 LeetCode」系列文章的第 No.671 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。


在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
|
19天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的眼疾识别系统实现~人工智能+卷积网络算法
眼疾识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了4种常见的眼疾图像数据集(白内障、糖尿病性视网膜病变、青光眼和正常眼睛) 再使用通过搭建的算法模型对数据集进行训练得到一个识别精度较高的模型,然后保存为为本地h5格式文件。最后使用Django框架搭建了一个Web网页平台可视化操作界面,实现用户上传一张眼疾图片识别其名称。
81 4
基于Python深度学习的眼疾识别系统实现~人工智能+卷积网络算法
|
1月前
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
300 55
|
29天前
|
存储 缓存 监控
局域网屏幕监控系统中的Python数据结构与算法实现
局域网屏幕监控系统用于实时捕获和监控局域网内多台设备的屏幕内容。本文介绍了一种基于Python双端队列(Deque)实现的滑动窗口数据缓存机制,以处理连续的屏幕帧数据流。通过固定长度的窗口,高效增删数据,确保低延迟显示和存储。该算法适用于数据压缩、异常检测等场景,保证系统在高负载下稳定运行。 本文转载自:https://www.vipshare.com
124 66
|
1天前
|
存储 算法 安全
控制局域网上网软件之 Python 字典树算法解析
控制局域网上网软件在现代网络管理中至关重要,用于控制设备的上网行为和访问权限。本文聚焦于字典树(Trie Tree)算法的应用,详细阐述其原理、优势及实现。通过字典树,软件能高效进行关键词匹配和过滤,提升系统性能。文中还提供了Python代码示例,展示了字典树在网址过滤和关键词屏蔽中的具体应用,为局域网的安全和管理提供有力支持。
31 17
|
2月前
|
搜索推荐 Python
利用Python内置函数实现的冒泡排序算法
在上述代码中,`bubble_sort` 函数接受一个列表 `arr` 作为输入。通过两层循环,外层循环控制排序的轮数,内层循环用于比较相邻的元素并进行交换。如果前一个元素大于后一个元素,就将它们交换位置。
151 67
|
2月前
|
存储 搜索推荐 Python
用 Python 实现快速排序算法。
快速排序的平均时间复杂度为$O(nlogn)$,空间复杂度为$O(logn)$。它在大多数情况下表现良好,但在某些特殊情况下可能会退化为最坏情况,时间复杂度为$O(n^2)$。你可以根据实际需求对代码进行调整和修改,或者尝试使用其他优化策略来提高快速排序的性能
140 61
|
2月前
|
算法 数据安全/隐私保护 开发者
马特赛特旋转算法:Python的随机模块背后的力量
马特赛特旋转算法是Python `random`模块的核心,由松本真和西村拓士于1997年提出。它基于线性反馈移位寄存器,具有超长周期和高维均匀性,适用于模拟、密码学等领域。Python中通过设置种子值初始化状态数组,经状态更新和输出提取生成随机数,代码简单高效。
130 63
|
1月前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
199 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
16天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
40 2
|
26天前
|
算法 网络协议 Python
探秘Win11共享文件夹之Python网络通信算法实现
本文探讨了Win11共享文件夹背后的网络通信算法,重点介绍基于TCP的文件传输机制,并提供Python代码示例。Win11共享文件夹利用SMB协议实现局域网内的文件共享,通过TCP协议确保文件传输的完整性和可靠性。服务器端监听客户端连接请求,接收文件请求并分块发送文件内容;客户端则连接服务器、接收数据并保存为本地文件。文中通过Python代码详细展示了这一过程,帮助读者理解并优化文件共享系统。