每日一题——力扣100. 相同的树(举一反三+思想解读+逐步优化)四千字好文

news2025/1/12 1:01:48


一个认为一切根源都是“自己不够强”的INTJ

个人主页:用哲学编程-CSDN博客
专栏:每日一题——举一反三
Python编程学习
Python内置函数

Python-3.12.0文档解读

目录

 我的写法

代码分析

时间复杂度分析

空间复杂度分析

总结

我要更强

时间复杂度和空间复杂度分析

哲学和编程思想

递归与迭代的哲学:

分而治之(Divide and Conquer):

抽象与具体化:

空间与时间的权衡:

数据结构的选择:

算法优化:

举一反三


题目链接:https://leetcode.cn/problems/same-tree/description/

 我的写法

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/*
解题思路:
首先比较根节点是否相同,然后分别比较左右子树是否相同。
*/
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p == NULL && q != NULL)
        return false;
    if(p != NULL && q == NULL)
        return false;
    if(p == NULL && q == NULL)
        return true;
    
    if(p->val == q->val)
        return  isSameTree(p->left, q->left)
                && isSameTree(p->right, q->right);
    else
        return false;
}

这段代码是用于判断两棵二叉树是否相同的算法。下面是对这段代码的专业点评:

代码分析

  1. 边界条件处理:
    • 代码首先处理了两个节点都为空的情况,此时认为两棵树相同。
    • 然后处理了其中一个节点为空而另一个不为空的情况,此时认为两棵树不同。
  2. 递归比较:
    • 当两个节点都不为空时,比较它们的值是否相等。
    • 如果值相等,则递归地比较它们的左子树和右子树。
  3. 返回值:
  • 如果两个节点的值不相等,直接返回false。
  • 如果值相等,返回左子树和右子树比较结果的逻辑与(&&)。

时间复杂度分析

  • 最坏情况:每棵树的每个节点都需要被访问一次,因此时间复杂度为O(n),其中n是节点数较多的那棵树的节点总数。
  • 平均情况:同样为O(n)。

空间复杂度分析

  • 最坏情况:如果树是完全不平衡的(例如,每个节点都只有一个子节点),递归调用的栈深度将达到n,因此空间复杂度为O(n)。
  • 平均情况:如果树是平衡的,递归调用的栈深度将大约为log(n),因此空间复杂度为O(log n)。

总结

这段代码简洁高效,正确地实现了判断两棵二叉树是否相同的功能。通过递归的方式,代码逻辑清晰,易于理解和维护。时间复杂度在最坏情况下为O(n),空间复杂度在最坏情况下为O(n),在平均情况下为O(log n),这使得它在处理大规模数据时也能保持较好的性能。


我要更强

为了优化时间复杂度和空间复杂度,我们可以考虑以下几种方法:

  1. 迭代方法(使用栈): 这种方法通过使用栈来模拟递归过程,可以减少递归调用栈的空间消耗。
  2. 前序遍历: 通过前序遍历两棵树,并比较每个节点的值,可以确保两棵树的结构和值都相同。

下面是使用迭代方法(使用栈)的完整代码:

#include <stdbool.h>
#include <stdlib.h>

// 定义树节点结构
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    // 使用栈来模拟递归过程
    struct TreeNode** stackP = (struct TreeNode**)malloc(sizeof(struct TreeNode*));
    struct TreeNode** stackQ = (struct TreeNode**)malloc(sizeof(struct TreeNode*));
    int topP = -1;
    int topQ = -1;

    // 将根节点入栈
    if (p != NULL) {
        stackP[++topP] = p;
    }
    if (q != NULL) {
        stackQ[++topQ] = q;
    }

    while (topP >= 0 || topQ >= 0) {
        // 出栈并比较节点
        if (topP < 0 || topQ < 0) {
            // 如果其中一个栈已经空了,说明两棵树不同
            return false;
        }

        struct TreeNode* nodeP = stackP[topP--];
        struct TreeNode* nodeQ = stackQ[topQ--];

        if (nodeP->val != nodeQ->val) {
            // 如果节点值不同,返回false
            return false;
        }

        // 将左右子节点入栈
        if (nodeP->right != NULL) {
            stackP[++topP] = nodeP->right;
        }
        if (nodeQ->right != NULL) {
            stackQ[++topQ] = nodeQ->right;
        }
        if (topP < 0 || topQ < 0) {
            // 如果其中一个栈已经空了,说明两棵树不同
            return false;
        }

        if (nodeP->left != NULL) {
            stackP[++topP] = nodeP->left;
        }
        if (nodeQ->left != NULL) {
            stackQ[++topQ] = nodeQ->left;
        }
        if (topP < 0 || topQ < 0) {
            // 如果其中一个栈已经空了,说明两棵树不同
            return false;
        }
    }

    // 释放动态分配的内存
    free(stackP);
    free(stackQ);

    // 如果所有节点都相同,返回true
    return true;
}

时间复杂度和空间复杂度分析

  • 时间复杂度:O(n),其中n是节点数较多的那棵树的节点总数。每个节点都会被访问一次。
  • 空间复杂度:O(n),在最坏情况下,栈的大小可以达到树的深度,即树的节点数。

这种方法通过使用栈来模拟递归,减少了递归调用栈的空间消耗,但并没有减少时间复杂度。在实际应用中,这种方法的性能可能会受到栈操作的影响,但对于大多数情况,它仍然是一个有效的解决方案。


哲学和编程思想

在解决这个问题时,我们运用了以下哲学和编程思想:

  1. 递归与迭代的哲学:

    • 递归:递归是一种自我调用的方法,它依赖于问题的分解,将大问题分解为小问题,直到问题变得足够简单可以直接解决。在原始的递归解决方案中,我们使用了递归的思想来比较两棵树的节点。
    • 迭代:迭代是通过循环结构重复执行一组操作,直到满足某个条件为止。在优化后的解决方案中,我们使用栈来模拟递归过程,这是一种迭代的思想。迭代通常比递归更节省空间,因为它避免了函数调用栈的额外开销。
  2. 分而治之(Divide and Conquer):

    • 这个策略是将一个复杂的问题分解成两个或更多的相同或相似的子问题,再将子问题分解,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。在比较两棵树是否相同的问题中,我们通过递归地比较左右子树来实现分而治之的思想。
  3. 抽象与具体化:

    • 在编程中,我们抽象出树的节点结构,并定义了节点之间的关系(左右子节点)。这种抽象使得我们可以专注于树的逻辑结构,而不必关心具体的实现细节。
  4. 空间与时间的权衡:

    • 在优化解决方案时,我们考虑了空间和时间的权衡。原始的递归解决方案在时间上是高效的(O(n)),但在空间上可能会有较高的开销(O(n)的递归调用栈)。通过使用迭代和栈,我们减少了空间的使用,但时间复杂度保持不变。
  5. 数据结构的选择:

    • 栈是一种后进先出(LIFO)的数据结构,它在处理树的遍历问题时非常有用。在这个问题中,我们使用栈来存储待比较的节点,这是一种有效的数据结构选择,因为它模拟了递归调用的过程。
  6. 算法优化:

  • 通过将递归转换为迭代,我们优化了算法的空间复杂度。这是一种常见的算法优化技巧,特别是在处理深度较大的树时,可以避免栈溢出的风险。

这些哲学和编程思想是解决复杂问题时常用的方法,它们帮助设计出更高效、更易于理解和维护的代码。在实际编程中,理解这些思想并灵活运用它们是非常重要的。


举一反三

掌握这些哲学和编程思想后,你可以将它们应用到更广泛的编程和问题解决场景中。以下是一些技巧,帮助举一反三:

  1. 递归与迭代的转换:
    • 当你遇到一个递归问题时,思考是否可以通过迭代和适当的数据结构(如栈或队列)来解决。这种转换通常可以减少空间复杂度,避免递归带来的额外开销。
  2. 分而治之策略:
    • 对于复杂问题,尝试将其分解为更小的、可管理的部分。例如,在处理数组或字符串问题时,可以考虑将它们分割成子数组或子串,分别处理后再合并结果。
  3. 抽象与具体化:
    • 在设计数据结构或算法时,首先抽象出问题的核心概念和关系,然后具体化这些概念以实现代码。例如,在设计一个社交网络应用时,首先抽象出用户、关系和消息等概念,然后定义这些概念的具体实现。
  4. 空间与时间的权衡:
    • 在优化算法时,始终考虑时间和空间的权衡。有时为了提高时间效率,可能需要牺牲一些空间;反之亦然。理解这种权衡可以帮助你做出更合理的决策。
  5. 选择合适的数据结构:
    • 根据问题的特点选择合适的数据结构。例如,如果问题涉及元素的插入和删除,链表可能是一个好选择;如果需要快速查找,数组或哈希表可能更合适。
  6. 算法优化:
    • 不断寻找改进算法的机会。例如,使用动态规划来避免重复计算,或者使用位操作来提高效率。
  7. 模式识别:
    • 学会识别问题中的常见模式,如树的遍历、图的搜索、排序和搜索算法等。一旦识别出模式,就可以应用已知的解决方案或算法。
  8. 测试和调试:
    • 在编写代码时,始终考虑如何测试和调试。良好的测试策略可以帮助你快速发现和修复问题。
  9. 代码重用:
    • 尽可能重用代码。如果某个功能或算法已经在其他地方实现,考虑是否可以直接使用或稍作修改后使用。
  10. 持续学习:
  • 编程和算法的世界不断发展,新的技术和思想层出不穷。保持好奇心和学习态度,不断更新你的知识和技能。

通过实践这些技巧,将能够更有效地解决问题,并在编程中展现出更高的创造力和灵活性。记住,编程不仅仅是写代码,更是一种思维方式和解决问题的艺术。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1862856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿尔兹海默症-图像分类数据集

阿尔兹海默症-图像分类数据集 数据集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1gSUT74XrnHmg2Z11oZNd6A?pwdwphh 提取码&#xff1a;wphh 数据集信息介绍&#xff1a; 文件夹 健康 中的图片数量: 8000 文件夹 早期轻度认知障碍 中的图片数量: 10000 文件夹 …

RabbitMQ中lazyqueue队列

lazyqueue队列非常强悍 springboot注解方式开启 // 使用注解的方式lazy.queue队列模式 非常GoodRabbitListener(queuesToDeclare Queue(name "lazy.queue",durable "true",arguments Argument(name "x-queue-mode",value "lazy&…

【MySQL进阶之路 | 高级篇】InnoDB存储结构(页的内部结构)

1. 数据库的存储结构 : 页 索引结构给我们提供了高效的索引方式&#xff0c;不过索引信息以及数据记录都是保存在文件上的.确切说是存储在页结构中.另一方面&#xff0c;索引是在存储引擎中实现的&#xff0c;MySQL服务器上的存储引擎负责对表中数据的读取和写入操作.不同的存…

【前后端实现】AHP权重计算

AHP权重计算&#xff1a; 需求&#xff1a;前端记录矩阵维度、上三角值&#xff0c;后端构建比较矩阵、计算权重值并将结果返回给前端 比较矩阵构建 如果你想要根据上三角&#xff08;不包括对角线&#xff09;的值来构建对称矩阵&#xff0c;那么你可以稍作修改上述的generate…

窗口控制

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 海龟绘图窗口就是在运行了导入turtle模块并调用了绘图方法的Python文件后&#xff0c;打开的窗口。该窗口默认的宽度为屏幕的50%&#xff0c;高度为屏…

怎么样才能让老旧的和颜色受损、丢失的照片重新上色呢?

怎么样才能让老旧的和颜色受损、丢失的照片重新上色呢&#xff1f;大家有时候在家中打扫卫生的时候&#xff0c;偶然发现了自己爸爸妈妈以前拍的照片&#xff0c;但是照片颜色已经受损的很严重了&#xff0c;几乎就是黑白的颜色&#xff0c;很难看清楚爸爸妈妈年轻时候的样子&a…

OpenAI开发者大会:OpenAI如何再次掀起AI领域的浪潮

对于AI行业的从业者来说&#xff0c;他们可能度过了一个不眠之夜。 北京时间2023年11月7日凌晨&#xff0c;美国人工智能公司OpenAI的开发者大会隆重举行。OpenAI的创始人Sam Altman与同事仅用短短45分钟的时间&#xff0c;在台上发布了他们团队的最新成果——GPT-4 Turbo。这一…

【React】portal

createPortal 允许你将 JSX 作为 children 渲染至 DOM 的不同部分。 createPortal(children, domNode, key?) 使用 portal 渲染模态对话框 import NoPortalExample from "./components/NoPortalExample"; import PortalExample from "./components/PortalEx…

学法减分题库最新版,分享几个简单试用的学习和搜题工具 #微信#经验分享#知识分享

告别繁琐的查询步骤&#xff0c;用我们的拍照搜题功能&#xff0c;只需几秒钟&#xff0c;答案就出现在你眼前&#xff0c;让学习变得更加高效便捷。 1.减分侠 这是个辅助学分减分的公众号 根据新的学法减分考试大纲&#xff0c;涵盖小车、客车、货车、摩托车&#xff0c;各…

放弃 VS Code:新代码编辑器 Zed 的时代已经到来(附使用感受)

1.Zed 是什么&#xff1f; Zed 由 Nathan Sobo 和一个曾在 GitHub 开发 Atom 和 Tree-sitter 的团队开发。他们的目标是创建一个快速、简单且用户友好的代码编辑器&#xff0c;以提升开发人员的编码体验。以下是关于 Zed 历史的一些关键点&#xff1a; 起源&#xff1a;团队利…

菲律宾媒体PR发稿:谷歌SEO优化.关键词排名.谷歌收录

1. 引言 在菲律宾&#xff0c;媒体行业的发展日新月异&#xff0c;尤其是在线媒体。为了在这个竞争激烈的市场中脱颖而出&#xff0c;各家媒体纷纷寻求谷歌SEO优化、提升关键词排名和增加谷歌收录的方法。本文将围绕菲律宾的几大主要在线媒体&#xff0c;如菲律宾在线日志Jour…

计算机系统基础知识(下)

嵌入式系统以及软件 嵌入式系统是为了特定应用而专门构建且将信息处理过程和物理过程紧密结合为一体的专用计算机系统&#xff0c;这个系统目前以涵盖军事&#xff0c;自动化&#xff0c;医疗&#xff0c;通信&#xff0c;工业控制&#xff0c;交通运输等各个应用领域&#xff…

Qwen2本地web Demo

Qwen2的web搭建(streamlit) 千问2前段时间发布了&#xff0c;个人觉得千问系列是我用过最好的中文开源大模型&#xff0c;所以这里基于streamlit进行一个千问2的web搭建&#xff0c;来进行模型的测试 一、硬件要求 该文档中使用的千问模型为7B-Instruct&#xff0c;需要5g以…

【大数据】大数据时代的黎明

目录 前言 深入解读大数据的本质 大数据的起源与演进轨迹 大数据对社会经济的深远影响 经济领域的革新 社会治理与公共服务的智能化 创新体系的重构 面临的挑战与应对 前言 步入21世纪以来&#xff0c;人类文明正站在一个历史性的转折点上&#xff0c;迎来了大数据时代的…

关于如何更好管理好数据库的一点思考

本文尝试从数据库设计理论、ER图简介、性能优化、避免过度设计及权限管理方面进行思考阐述。 一、数据库范式 以下通过详细的示例说明数据库范式的概念&#xff0c;将逐步规范化一个例子&#xff0c;逐级说明每个范式的要求和变换过程。 示例&#xff1a;学生课程登记系统 初始…

汽车零部件制造企业如何选择合适的ESOP电子作业指导书系统

随着汽车产业的不断发展&#xff0c;汽车零部件制造企业在提高生产效率和产品质量方面面临着越来越大的挑战。为了解决这些问题&#xff0c;越来越多的汽车零部件制造企业开始采用ESOP电子作业指导书系统&#xff0c;以帮助他们管理和优化生产流程。但是&#xff0c;在选择合适…

win7使用vue-cli创建vue3工程

1.创建名为test的项目 vue create test 回车以后选择第三个,进行手动选择 2.选择配置 向下箭头表示下一个&#xff0c;空格表示*选中&#xff0c;按照我的选择来选即可&#xff0c;选完后回车 3.选择vue.js版本 上线箭头进行选择&#xff0c;选择后回车 4.选择不同的配置&#…

一个实例配置多个服务名

更改参数实现配置多个服务名 需求背景 在做案例模拟的时候发现博主的环境配置的是3个服务名&#xff0c;通常都是一个服务名&#xff0c;服务名就是数据库名&#xff0c;出于好奇进行了以下实验。 环境&#xff1a;Oracle 11.2.0.4 单点 配置多个服务名的意义 可以通过服务…

【CT】LeetCode手撕—72. 编辑距离

目录 题目1- 思路动规五部曲 2- 实现⭐72. 编辑距离——题解思路 3- ACM 实现 题目 原题连接&#xff1a;72. 编辑距离 1- 思路 模式识别&#xff1a;编辑举例 ——> 动态规划 动规五部曲 1.dp数组的含义 int[][] dp new int[word1.length()][word2.length()];以 i-1 …

正则表达式;grep、sed、awk、soft、uniq、tr 详解

正则表达式 概念 正则表达式&#xff08;Regular Expression&#xff0c;常简写为regex、regexp或RE&#xff09;是一种强大的文本处理工具&#xff0c;它使用一种特殊的字符序列来帮助用户检查一个字符串是否与某种模式匹配。 标准正则表达式 首先安装正则表达式pcre库 创…