贵州省铁路建设办公室网站seo搜索引擎优化费用

张小明 2026/1/11 4:01:44
贵州省铁路建设办公室网站,seo搜索引擎优化费用,紫金银行网站,欧式建筑网站最近在做 LeetCode 450#xff08;删除二叉搜索树中的节点#xff09;时#xff0c;我写出了一版执行用时 0ms#xff0c;击败 100% 用户的代码。 从算法效率上讲#xff0c;它是完美的#xff1a;纯指针操作#xff0c;没有递归开销#xff0c;逻辑硬核。 但从工程角度…最近在做 LeetCode 450删除二叉搜索树中的节点时我写出了一版执行用时 0ms击败 100% 用户的代码。 从算法效率上讲它是完美的纯指针操作没有递归开销逻辑硬核。 但从工程角度讲它是十足的垃圾代码可能下周我自己都看不明白我写的什么玩意了。今天这篇博客我想通过复盘这段代码聊聊如何把代码从“能跑”进化到“能读”。第一阶段原始代码我的核心思路非常直接物理断开与重连。 不搞递归那种值拷贝直接找到节点找到它的前驱左子树最右节点把前驱拎出来物理替换掉目标节点。这是我提交的原始版本已通过所有测试用例// 此代码虽然性能极致但是问题一堆写得一塌糊涂。 class Solution { public: TreeNode* deleteNode(TreeNode* root, int key) { // 【段落 1】 处理空节点的情况 if (!root) { return nullptr; } // 【段落 2】 处理key节点是根节点的情况 // 这里的逻辑没有父节点直接操作 root if (root-val key) { if (!root-left !root-right) { return nullptr; } else if (!root-left root-right) { return root-right; } else if (root-left !root-right) { return root-left; } else if (root-left root-right) { //复杂的双子节点处理逻辑 TreeNode* old1 root;// 【角色被删节点】 (这里就是root本身) TreeNode* old2 root;// 【角色前驱节点的父节点】 (初始跟被删节点一样) root root-left; while (root-right) {//潜在巨雷 root去当游标了 old2 root; root root-right; } if (old1 old2) { //说明这个左节点就是左子树最右的节点了 root-right old1-right; return root; } else if (old1 ! old2) { old2-right nullptr; root-right old1-right; TreeNode* t root; while (t-left) { t t-left; } t-left old1-left; return root; } } } // 【段落 3】 key节点不是根节点的情况 TreeNode* old0 root; // 保存原始根 (最后要返回它) TreeNode* old1 root; // 【角色被删节点的父节点】 (上半部分没有因为上半部分没父节点) TreeNode* old2 root; // 【角色被删节点 / 目标节点】 (初始是root后面会变成目标) // 1. 先找到要删除的节点 while (root root-val ! key) {//潜在巨雷 root去当游标了 if (root-val key) { old1 root;// old1 紧跟 root 充当父节点 root root-left; } else { old1 root;// old1 紧跟 root 充当父节点 root root-right; } } // 没找到直接返回 if (!root) { return old0; } // 到这里root 指向的就是【要被删除的节点】 // 下面的逻辑开始处理删除 root (即 old2) 的操作 // 情况 1: 叶子节点 if (!root-left !root-right) { if (old1-left root) { old1-left nullptr; return old0; } else { old1-right nullptr; return old0; } } // 情况 2: 只有右孩子 else if (!root-left root-right) { if (old1-left root) { old1-left root-right; return old0; } else { old1-right root-right; return old0; } } // 情况 3: 只有左孩子 else if (root-left !root-right) { if (old1-left root) { old1-left root-left; return old0; } else { old1-right root-left; return old0; } } // 情况 4: 左右孩子都有 (最晕的地方来了) else if (root-left root-right) { // 此时 root 是【要被删除的节点】 old2 root;// 【角色被删节点】 -- 对应上半部分的 old1 TreeNode* old3 root;// 【角色前驱节点的父节点】 -- 对应上半部分的 old2 // 开始寻找前驱 (左子树的最右节点) root root-left; while (root-right) { old3 root;// old3 紧跟记录前驱的父亲 root root-right; } // 循环结束后root 变成了【前驱节点】(用来顶替被删节点的那个人) // 下面的逻辑和上半部分是完全镜像的只是变量名下标1了 // 特例前驱节点的父节点 就是 被删节点本身 (即左子树没有右分支) if (old3 old2) { if (old1-left old2) { root-right old2-right; old1-left root; return old0; } else { root-right old2-right; old1-right root; return old0; } } // 通用情况前驱节点在深处 // 此时old1(爷爷), old2(被删), old3(前驱父), root(前驱) else if (old3 ! old2) { old3-right nullptr; root-right old2-right; TreeNode* t root; while (t-left) { t t-left; } t-left old2-left; if (old1-left old2) { old1-left root; return old0; } else { old1-right root; return old0; } return old0; } } return root; } };第二阶段局部分析这代码就是我一边想一边写的产物脑子里在想各种情况如何处理然后就实时写出各分支游标、变量都是随时需要随时定义随时使用。等写完我自己再复盘的时候都没绷住虽然能通过但是实在是太有槽点了以至于我必须新开一篇blog记录一下我到底是怎么写出这种代码以及该如何改进的。我们一行行来分析问题出在哪1. 变量命名陷阱TreeNode* old0 root; TreeNode* old1 root; TreeNode* old2 root; TreeNode* old3 root; // 在某些分支里还有 old3问题old家族大团结我的小巧思。但old是什么意思旧的老的old0到old3之间是什么关系这种命名迫使阅读者必须在脑子里维护一张映射表old1父亲, old2目标…。一旦代码逻辑变复杂这张表瞬间就会崩塌。代码失去了自解释能力。更要命的是上下两部分的old1、old2甚至代表的含义都不一样。2. 逻辑分裂if (root-val key) { ... } // 处理 Root // ... while (root root-val ! key) { ... } // 处理非 Root问题上半部分和下半部分的删除逻辑叶子、单边、双边是完全一样的仅仅因为根节点没有父节点我就把代码复制了一遍。这导致任何一次逻辑修正比如修复 BST 断链 bug都需要改两个地方漏改一处就是事故。3. 指针复用混乱while (root root-val ! key) { root root-left; // root 变成了游标 } return old0; // 最后不得不返回保存的 old0问题root指针在函数里身兼数职它是树的入口是遍历的游标又是某些分支的返回值。这种“一鱼多吃”的做法极大地增加了认知负荷。输入参数应尽量保持只读或语义稳定。4. 控制流层层递进代码缩进呈现可怕的箭头状。问题if套ifelse连else。这种深层嵌套掩盖了主要逻辑流。第三阶段架构调整在开始改代码之前我们需要先在脑海里重构模型。如何消除 Root 和非 Root 的区别如何让逻辑变清晰 答案是逻辑分层。原始代码是“边找边删”重构代码应该是流水线作业Search定位统一找到目标节点target和它的父节点parent。Decide决策决定谁来接班replacement。Link缝合统一执行指针连接操作。核心在算法眼里Root 只是一个parent为nullptr的普通节点。引入parent变量且专门处理一下parent为nullptr时的情况两套逻辑瞬间就能合并为一套。第四阶段重构基于上述分析保留我核心的“物理断开前驱”的高效逻辑重构后的代码如下。请对比阅读class Solution { public: TreeNode* deleteNode(TreeNode* root, int key) { // 1. 处理空树减少一层嵌套 if (!root) return nullptr; // 2. 统一查找逻辑 // 使用语义化变量target (目标), parent (父亲) TreeNode* target root; TreeNode* parent nullptr; while (target target-val ! key) { parent target; // 父节点紧跟其后 if (key target-val) { target target-left; } else { target target-right; } } // 没找到直接返回 if (!target) return root; // 3. 决定谁来接班 (replacement) TreeNode* replacement nullptr; // 情况 A: 左右双全 (最复杂的逻辑保留原版的高效思路) if (target-left target-right) { // 语义化变量predecessor (前驱), predParent (前驱的父亲) TreeNode* predecessor target-left; TreeNode* predParent target; // 寻找左子树的最右节点 while (predecessor-right) { predParent predecessor; predecessor predecessor-right; } // 处理前驱的“身后事” if (predParent ! target) { predParent-right predecessor-left; // 爷爷接管孙子的左孩子 predecessor-left target-left; // 前驱接管目标的左臂膀 } // 前驱接管目标的右臂膀 predecessor-right target-right; // 选定接班人 replacement predecessor; } // 情况 B: 只有左孩子 else if (target-left) { replacement target-left; } // 情况 C: 只有右孩子 else if (target-right) { replacement target-right; } // 情况 D: 叶子节点 (replacement 保持为 nullptr) else { replacement nullptr;//这一块可以不写写也只是为了清晰一点。 } // 4. 【缝合阶段】统一执行连接 // 这一步彻底消除了 Root 和 非 Root 的代码重复 if (!parent) { // 如果没有父亲说明删的是 Root直接换头 root replacement; } else { // 如果有父亲让父亲指向新的接班人 if (parent-left target) { parent-left replacement; } else { parent-right replacement; } } // 此时整棵树的结构已完整统一返回 return root; } };总结从old0/old1/old2/old3到target/parent/predecessor/predParent从“两坨逻辑”到“一条流水线”。这次重构没有改变算法的时间复杂度依然是 0ms但它改变了代码的生命周期。原始代码写完即死难以维护我自己写自己看都绷不住。重构代码逻辑清晰结构稳健任何人接手捋捋都能看懂。写出计算机能跑的代码只能算是一种本能而写出让人能读懂最起码能让未来的自己看懂的代码(难绷)才是真正的本事。以前看到过一句话好看的武器一定好用。我想好的代码也应该具备这种品质优雅美丽高效简洁。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

建网站买完域名后怎么做网站建设方案书 个人

浙大疏锦行 1.模型结构可视化 理解一个深度学习网络最重要的2点: 1. 了解损失如何定义的,知道损失从何而来----把抽象的任务通过损失函数量化出来 2. 了解参数总量,即知道每一层的设计才能退出---层设计决定参数总量 为了了解参数总量&a…

张小明 2026/1/4 8:13:17 网站建设

企业网站的优劣势嵌入式培训学费

深入解析IP过滤与防火墙:iptables技术详解 1. 规则匹配与分支处理 在规则匹配过程中,若分支链中没有规则匹配,我们需要返回到分支点所在的链,并从离开的位置开始扫描该链中的下一条规则。若未设置分支,我们会查看 simplebranch 字段来决定下一步操作: - 若该字段设置…

张小明 2026/1/4 8:13:14 网站建设

免费建站哪家好保险网上预约

近年来,数字媒体艺术设计专业的毕业生面临着前所未有的机遇与挑战。行业数字化进程加速,企业对人才的要求从单一的设计技能扩展到数据分析、用户体验、项目管理等复合能力。根据多所高职院校的培养方案,学生在校期间可考取多种专业证书&#…

张小明 2026/1/4 8:13:15 网站建设

建设厅注册中心网站苏州网页制作找哪家

很多人对 Prompt 的差异没有直觉。这一篇,我们用同一个 UI 需求,对比「坏 Prompt」和「好 Prompt」,看看结果到底能差多远。 场景设定 目标:生成一个轻量级客户管理小程序的客户列表页。用户:非技术背景的销售人员。 《…

张小明 2026/1/4 8:13:15 网站建设

上海网站开发有限公司可视化自助建站

3分钟精通WindowResizer:彻底解决窗口尺寸管理的三大痛点 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 还在为那些无法调整大小的顽固窗口而烦恼?WindowR…

张小明 2026/1/5 15:06:57 网站建设

广州免费推广网站建设wordpress 问答 主题 knowhow

深夜的实验室里,最后一组数据刚刚整理完毕,研究生李明的焦虑却刚刚开始——这篇凝聚了两年心血的论文,究竟该投向哪本期刊?这个场景在全球研究者的日常中反复上演。深夜的研究生工作室里,屏幕蓝光映着一张疲惫的脸&…

张小明 2026/1/10 12:59:33 网站建设