每日一遍,BUG再见!程序员bug修复宝典重现天日!

2024-02-02 17:38

本文主要是介绍每日一遍,BUG再见!程序员bug修复宝典重现天日!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

bug,又名程序缺陷或者程序漏洞,是每个程序员每天都回避不了的东西。程序员对bug的感情可谓是五味杂陈:一方面bug非常可恶,尤其是一些偶现的bug,它强大到可以摧毁一个优秀程序员的意志;另一方面很多bug又是程序员自己亲手写下的,无奈之余只能自嘲一句:不写bug我们就要失业了!

作为一名职业程序员,同时也是一名开源创作者, 夸张点说,我解过的bug可以绕地球一圈, 每天写bug解bug几乎是我的日常。

但是,作为一个善于思考和总结的技术博主,我怎么能止步于每天写bug和解bug呢?更何况,人生在世,总得有点追求。既然我不能够阻止bug的产生,那么就让我总结一点bug的修复技巧,让bug消失地更快点吧!

1.bug修复的生命周期

中医讲究"望闻问切",其实修复一个bug就像给病人看一场病,本质上是相通的。

当我们遇到一个bug(问题)的时候,一般我们需要经历如下6个步骤:

  • 1.了解bug。我们首先需要到底出了什么bug,现象是什么,怎样发生的。
  • 2.复现bug。在了解了bug的大致情况之后,我们需要能够找到复现的路径,这就为后面bug的定位提供可靠的依据。
  • 3.定位bug。当有了稳定的复现途径之后,要做的就是打断点、打日志进行调试,来一步一步分析和定位bug,到底是那块代码导致的错误。
  • 4.确认bug。当我们定位到bug出错的地方之后,我们就需要分析这到底是不是bug。如果是bug,那么这个bug出现的根源是什么,到底能不能解决。
  • 5.修复bug。在明确了bug的根本原因之后,下面就需要发挥我们的聪明才智去修复这个bug了。
  • 6.验证bug。并不是每次我们修复完bug之后就可以万事大吉了,此时我们还需要去重现bug以确保bug被真正修复。除此之外,有条件的我们还需要去验证相关场景,以保证修复该bug不会引入其他bug。

以上可以总结为12字方针–"了解、复现、定位、确认、修复、验证"bug。 一般在稍微大一点的公司,都会有对应的流程对bug的修复进行流程控制,最终形成闭环。

可以看到的是,其实修复bug只是解决一个bug的6个步骤中的其中一步。很多刚刚参与工作的程序员经常犯的错误就是一遇到bug,就开始漫无目的地看代码或者是上网各种瞎搜索,又或者各种无脑问,最后搞了一圈可能连自己要解决的bug到底是什么都不知道,这样解决bug的效率可想而知。

可能读到这的你此刻非常想问:怎样才可以更快地修复一个bug呢?那么下面我就根据上面讲的六个步骤来分别讲解一下对应的技巧。

2.解决bug的艺术

在我看来,修复一个bug是相对容易的。因为修复一个bug的方法可能有很多种,但是如何从根本上解决一个bug,并保证这个bug下次不再复现的话,其实是非常难的,这就需要我们学习一下解决bug的艺术。

2.1 了解bug

俗话说,知己知彼百战不殆。bug修复的第一步当然是先了解bug了。

了解bug是解决bug最重要的一步,它直接决定了后面五步执行的效率和质量。糟糕的错误报告和不负责任的问题描述都是埋葬程序员修复bug意志的罪魁祸首。

在了解bug之前,我们需要收集足够的信息,了解它产生的现象、描述、复现步骤、以及解决后的预期是什么等等。那么我们应该怎么做才能更加全面地了解它呢?

下面我给几点建议供大家参考:

2.1.1 观察现象

光凭文字说明是无法准确领悟到bug的精髓的。因为每个人思考问题的角度以及文字表达描述都是千差万别的。

如果说这个时候能提供一段出错的视频或者问题截图,又或者能够现场演示错误的话,这样观察现象,然后再结合问题描述之后,一定能够帮助你快速地了解这个bug。

2.1.2 询问相关人员

这里你询问的可以不仅限于发现bug的人(一般是测试人员),当然你首先应当询问的还是这个发现bug的人。

这里你需要着重询问bug报告上你觉得迷惑的点,比如出现bug的应用版本、设备型号、bug出现的频率、bug产生的步骤和恢复的途径、bug修复的预期效果等。这里你需要进行刨根问底地询问,因为可能bug发现人觉得一些无关紧要的细节,对你来说却是至关重要的点。

问完发现bug的人之后,我们还可以向bug对应模块的负责人(测试、开发、产品)询问该模块的业务逻辑,说不定能够获取到有价值的信息哦。

2.1.3 提供bug报告模板

一份优秀的bug报告模板,可以让程序员直接跳过bug修复的前三步,直接进入到确认bug步骤,从而能够极大地提高bug修复的效率。那么一份优秀的bug报告模板应当具备哪些内容呢?

  • bug的标题和问题描述
  • 出现bug的应用版本
  • 出现bug的设备信息(型号、版本等)
  • bug产生相关的视频、截图和错误日志
  • bug复现的步骤
  • bug出现的必要条件(环境)和恢复途径
  • bug修复后的预期效果
  • bug对应的模块或者关联bug

有了以上的内容之后,相信程序员能够很快地了解这个bug,定位出bug产生的原因并予以解决。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4gsQTUzh-1615192179158)(https://upload-images.jianshu.io/upload_images/25266384-7fa4b97bb5afb0ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

2.2 复现bug

如果你在第一步了解bug中获得了良好的bug报告的话,则此部分可以很容易。你只需要按照bug报告中的bug复现步骤,按顺序操作即可稳定复现bug。

当然,很多时候往往并不是一帆风顺的,即使你手握bug报告,做了非常详细的调查工作,然而bug就是无法复现,那么这个时候我们应该怎么做呢?

2.2.1 重新了解bug

此时为了能够复现bug,你可能需要回到上一步,重现去了解bug。因为你之前对bug的理解可能产生偏差,又或者你第一步并没有做好才导致了bug未能复现。这个时候带着疑问去重现了解bug,可能你会发现新的大陆。

2.2.2 将偶现bug转为必现bug

偶现bug算是bug家族中最调皮的一个了。它们以没有规律,难以复现等特性,经常能把以一个好好的程序员给逼疯。

但是既然是要复现bug,那么肯定要找到bug稳定复现的路径,这样才能方便下面bug的定位。这里我推荐大家的一个做法就是想办法把偶现的bug转化为必现的bug。因为即使是偶现的bug,很多也是特定条件下必现的bug,只不过此时你还没发现这个特定条件而已。

那么怎样才能将偶现bug转为必现bug呢?这里我简单介绍一下我常用的技巧:

  • 1.对比法:观察并对比复现和不复现的各方面条件,找到那个必现的特定条件。

  • 2.注释(删除)代码法:对怀疑的代码进行注释(删除),直到彻底将偶现bug转变为必现bug。

2.3 定位bug

一旦我们找到了bug稳定复现的步骤之后,下面的工作就是开始定位bug产生的地方了。

这一步可以说是解决bug的关键环节,这一步骤的难易程度一般取决于以下几个因素:

  • 1.程序员自身的代码量(工作经验)
  • 2.对项目代码(业务)的熟悉程度。
  • 3.分析问题和解决问题的能力

那么我们如何才能更快地定位出bug产生的位置呢?下面我提供一些思路供大家参考:

  • 1.断点调试法。这是程序员通用,同时也是最有效的定位问题的方式。一个不会断点调试的程序员和瞎子没有本质上的区别。
  • 2.日志分析法。其实并不是所有bug都可以进行断点调试的。比如在一些循环调用或者业务较为复杂的场景下,打日志分析定位是较为适合的方式。
  • 3.排除法。如果一个bug产生的原因可能有多种情况的时候,这个时候采取排除法的方式是最优的。你可以把可能导致bug产生的代码块都打上日志或者断点,然后重现一下bug进行问题的定位。
  • 4.代码回滚法。如果你这个bug在之前的版本是好的,但是在现在版本上又出现了,这个时候就可以使用代码回滚大法。把你的代码回滚到你怀疑的版本,运行看bug是否消失,然后对两个版本之前代码有何区别,最终定位出bug产生的位置。这里我们可以使用二分法来提高代码的回滚效率。
  • 5.注释(删除)代码法。这个我在上一个步骤中也提到过。对于一些难以理解和定位的bug,我们可以使用这个方法进行尝试。不过这个方法使用起来有一定的风险,因为可能你删除的那一串代码虽然能够解决bug,但是却不是bug产生的根源,这个时候你可能会将必现bug改成了偶现bug,让问题变得更加复杂。
  • 6.源码分析法。有的时候有些bug可能并不是你的代码导致的问题。可能是第三方库本身的bug,又或者是系统本身的bug,又或者是你误用api导致的问题,这个时候就需要你拥有源码分析的能力。深入源码中,一层层分析直到最终找到bug产生的原因。
  • 7.联想法。通过一些类似的bug修改经验从而联想猜测出bug产生的位置。这个方法对使用者本身有较高的要求。需要使用者对项目代码和业务逻辑非常熟悉,同时对问题分析的能力有较高的要求。这就是我们常说的牛人能够一眼就能看出问题,他们常用的就是这种方式。
  • 8.场外支援法。这是实在定位不出bug才采取的下下策。因为它并不能提高你定位bug的能力,同时请别人帮忙定位bug,你就需要把你之前所做的工作都要全盘地向他表述一遍,这样不仅会降低bug修复的效率,同时还不一定能保证定位出bug产生的位置,它取决于你表述问题的能力和帮你的人分析和解决问题的能力。


(看了这么久,看看美女放松下吧!)

2.4 确认bug

在我们定位出bug产生的位置后,下面的工作就是分析bug产生的根源了。

这一步可以说是bug修复6个步骤中最为关键的一步。这一步直接决定了这个bug能否被彻底地解决,同时也是最能体现bug修复艺术的步骤。

但是很遗憾的是,这一步往往被很多人给忽视了。我为什么会这样说呢?因为很多时候我们修复bug的时候,都会受到各方面的限制:

  • 1.自身经验水平的限制:一些初入项目的程序员经常因为修复一个bug而导致了另一个bug,又或者只是看到了bug的表象却不能感知到bug产生更深层次的原因,所以10种产生bug的情况他可能只改了一种,将必现问题改成了偶现问题,让bug变得更加复杂。
  • 2.时间限制:这是我们程序员经常碰到的限制。这在互联网企业非常普遍,通常解决一个bug是有时间限制的,例如:这个项目明天就要上线了,并强制要求你今晚就得想办法解决。这个时候你可能就被逼无奈,采取硬编码的方式去临时把这个bug给按住。其实这样虽然bug是被临时解决了,但是却会让这个bug变得愈加复杂。很多公司出现的那些祖传代码就是在这种情况下产生的,动一下就可能产生无数未知的bug,令人绝望。
  • 3.业务限制:很多时候导致代码逻辑非常复杂难懂的罪魁祸首就是这种业务限制。我们在修复一个bug的时候,很多时候就是因为这种业务的限制,导致bug的修复一种不能从根源上予以解决,只要业务一调整就可能导致这个bug反复地出现。

说了这么多限制,那么我们如何才能找到问题的根源呢?

  • 1.多积累经验,提升自身的水平:这是打破自身经验水平的限制。
  • 2.及时处理bug:在收到bug报告的第一时间就去处理,尽可能打破时间的限制。
  • 3.多熟悉业务:有时间就多去了解和梳理业务,深入研究项目代码。这样我们在解决bug的时候也不会因为对业务不熟悉而无法分析出bug产生的根源。
  • 4.准确定位bug:bug定位的准确性直接决定了你能否分析出bug产生的根源。因此你需要仔细分析和定位bug,使用我上面介绍的8种方式去定位bug。

2.5 修复bug

其实前面的四步都是为这一步所做的铺垫。有了前面四步的工作,相信到这儿也是相对微不足道的了,剩下的就是如何优美地解决这个bug了。

到了这个阶段,bug通常不需要大的修改来修复,因此这一步往往会非常快,当然也就没有什么好的技巧啦。

2.6 验证bug

作为bug修复的最后一步,它是确保bug被真正修复的最后保障。

在这里需要我们着重注意以下几点:

  • 1.重复之前复现bug的步骤来验证bug是否被彻底解决。
  • 2.验证bug修复可能改动到的相关模块是否正常,保证bug修复不引入新的bug。

如果上述有任何一点没有达到的话,请返回步骤四和步骤五,重新修复bug!

3.如何提高bug修复的效率

上文我们着重讲解了解决bug的艺术,为的是能够更好地解决bug。但是如何才能保证既有效,又快速地修复bug,提高bug修复的效率呢?

通过上面对于解决bug的艺术的讲解,我们可以总结出以下影响bug修复效率的几个关键点:

  • 1.bug信息收集的效率以及有效性。
  • 2.时间限制的压力。
  • 3.人员对项目代码(业务)的熟悉程度。
  • 4.人员自身经验和分析问题的能力。

以上4点可以说直接决定了bug修复的效率。那么如何才能提高bug修复的效率呢?下面我将一一给出我的看法。

我的心是冰冰的

3.1 建立健全的信息收集机制

bug信息的收集可以说是修复bug过程中最为耗时的环节。提升bug信息收集的效率以及有效性可以大幅度地提升我们修复bug的效率。

那么我们应该如何建立健全的信息收集机制呢?这里我给出我的几点建议:

3.1.1 提供优秀的bug报告模板

上文我们在了解bug一步中提到过:一份优秀的bug报告模板,可以让程序员直接跳过bug修复的前三步,直接进入到确认bug步骤,从而能够极大地提高bug修复的效率。

这里我再次重复一步,一份优秀的bug报告模板应当具备哪些内容:

  • bug的标题和问题描述
  • 出现bug的应用版本
  • 出现bug的设备信息(型号、版本等)
  • bug产生相关的视频、截图和错误日志
  • bug复现的步骤
  • bug出现的必要条件(环境)和恢复途径
  • bug修复后的预期效果
  • bug对应的模块或者关联bug
3.1.2 建立完备的日志体系

一套完备的日志体系,可以让我们更加清晰地知道用户到底做了什么才导致bug的出现。

在项目的初期,我们可能为了赶工期而常常忽视了日志打印的重要性,这很可能就会导致该项目日后的维护将非常得艰难。

那么我们为什么要建立一套完备的日志体系呢?

  • 1.并不是所有的用户(测试)都能够给你描述清楚bug产生的信息。
  • 2.即使用户(测试)给你描述了bug产生相关的信息,但是他们并不理解你的代码逻辑,他们只能根据bug出现的现象告诉你问题,可能他们的表述和你的理解不在一个频道。

如果你有这么一套完备的日志体系,那么你就可以在用户(测试)不用开口的情况下,直接get到用户的操作行为以及对于的代码逻辑。同时,可能一句关键点的报错日志就可以帮你直接定位到bug产生的位置,从而直接进入第四步确认bug

说了这么多,我们应该如何打印高效的日志呢?

  • 1.在异常分支返回前打印日志。
  • 2.在复杂业务流程的关键点打印日志。
  • 3.在对外交互或者模块交互点打印日志。
  • 4.在用户交互或者生命周期的关键点打印日志。
  • 5.对重要的信息点打印日志,记录用户画像。
  • 6.按重要性分等级打印日志。
  • 7.禁止在循环中打印日志,禁止打印无效的日志。
  • 8.禁止打印用户隐私相关的信息。

3.2 建立自动化测试机制

建立自动化测试机制,可以让突破时间限制成为可能。

3.2.1 更早地发现bug

很多时候来自时间限制的压力,往往是测试不充分导致的。很多bug直到产品临近上线或者交付的时候才被发现,这个时候唯一解决问题的方式就是在时间上做出限制,无情压迫我们这些活在公司权力最底层的程序员们。

如果这个时候能有一套自动化测试机制,每天下班后都进行自动测试的话,那样很多bug就能被提前发现,从而为我们修复bug预留了不少宝贵的时间。

3.2.2 节约bug验证的时间

对于一些复杂难解、偶现的bug,我们往往会在确认bug验证bug之间花费大量的时间。这个时候如果有一套自动化测试机制或者工具帮助我们验证bug的话,就可以极大地缩减我们修复bug的时间。

3.3 提高项目代码(业务)的熟悉程度

提高人员对项目代码(业务)的熟悉程度,这样就可以极大地提高人员定位bug的效率。

3.3.1 建立丰富的知识库体系

建立一套丰富的知识库体系,可以帮助我们加深对自己责任内项目代码(业务)的理解,同时还能帮助我们快速了解我们所不了解的业务模块。

那么如何才能建立起丰富的知识库体系呢?下面我给出我的几点建议:

  • 1.对知识进行分类。
  • 2.定期添加和更新知识库的内容。
  • 3.提高知识库的检索效率。
  • 4.定期组织知识的分享。
  • 5.激励贡献知识库的人员。
3.3.2 建立责任田划分机制

划分责任田的目的就是:让专业的人做专业的事情。

划分责任田的好处:

  • 1.专业的人做专业的事情。划分完责任田后,田主需要对自己负责的模块负责,这就必然要求其对模块内的代码(业务)更加熟悉。
  • 2.责任到人利于追责和bug跟踪。

当然责任田也不是想象中的那么完美,它也存在一定的缺陷:

  • 1.职责明确之后可能导致缺少全局视野。一些复杂的bug可能是几个模块共同作用下才产生的,对于这类bug的定位势必会大大增加难度。
  • 2.划分责任田之后,可能导致踢皮球的情况。

责任田划分机制,它是一把双刃剑。所以是否需要建立责任田划分机制,还是需要结合企业自身的情况而定的。

4.打铁还需自身硬

bug是永远都写不完的,而且程序员留在代码里不仅仅只有bug,还有时光。在解决一个有一个bug的同时,相应的自己能力有没有也得到提升呢?下次遇到同样的问题,会不会又是一脸蒙逼?简而言之,对于程序员而言,技术才是王道。应对bug最好的方法,还是不断的提升自己的技术!我自己作为一个Android开发者,应该能给你一些这样的帮助!

  • 4.1 架构师筑基必备技能

目前Android APP开发主流语言就是Java语言,Java语言最大的特性就是提高了软件的交互可能性,可以说安卓手机几乎所有应用程序都是利用Java语言来进行编写的。

知识要点:
1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO

架构师筑基必备技能

  • 4.2 设计思想解读开源框架

随着互联网企业的不断发展,产品项目中的模块越来越多,用户体验要求也越来越高,想实现小步快跑、快速迭代的目的越来越难,插件化技术应用而生。如果没有插件化技术,美团、淘宝这些集成了大量“app”的应用,可能会有几个g那么大。

所以,当今的Android移动开发,不会热修复、插件化、组件化,80%以上的面试都过不了。

知识要点:
1、热修复设计
2、插件化框架设计
3、组件化框架设计
4、图片加载框架
5、网络访问框架设计
6、RXJava响应式编程框架设计

设计思想解读开源框架

  • 4.3 360°全方位性能调优

在不同层次的开发工程师手里,因为技术水平的参差不齐,即使很多手机在跑分软件性能非常高,打开应用依然存在卡顿现象。

另外,随着产品内容迭代,功能越来越复杂,UI页面也越来越丰富,也成为流畅运行的一种阻碍。综上所述,对APP进行性能优化已成为开发者该有的一种综合素质,也是开发者能够完成高质量应用程序作品的保证。

1、设计思想与代码质量优化

2、程序性能优化

  • 启动速度与执行效率优化
  • 布局检测与优化
  • 内存优化
  • 耗电优化
  • 网络传输与数据储存优化
  • APK大小优化

3、开发效率优化

  • 分布式版本控制系统Git
  • 自动化构建系统Gradle

4、项目实战

  • 启动速度
  • 流畅度
  • 抖音在APK包大小资源优化的实践
  • 优酷响应式布局技术全解析
  • 网络优化
  • 手机淘宝双十一性能优化项目揭秘
  • 高德APP全链路源码依赖分析
  • 彻底干掉OOM的实战经验分享
  • 微信Android终端内存优化实践

360°全方位性能调优

  • 4.4 Android框架体系架构

Android框架体系架构(高级UI+FrameWork源码) 这块知识是现今使用者最多的,我们称之Android2013~2016年的技术。

Android开发者也往往因为网上Copy代码习惯了而导致对这块经常“使用”的代码熟悉而又陌生:熟悉的是几乎天天在和它们打交道, 天天在复制这些代码 ;陌生的是虽然天天和这些代码打交道,但是并没有深入研究过这些代码的原理,代码深处的内涵。

本篇知识要点:
1、高级UI晋升
2、Android内核组件
3、大型项目必备IPC
4、数据持久与序列化
5、Framework内核解析

Android框架体系架构

  • 4.5 NDK模块开发(音视频系列)

NDK(Native Development Kit缩写)一种基于原生程序接口的软件开发工具包,可以让您在 Android 应用中利用 C 和 C++ 代码的工具。通过此工具开发的程序直接在本地运行,而不是虚拟机。

在Android中,NDK是一系列工具的集合,主要用于扩展Android SDK。NDK提供了一系列的工具可以帮助开发者快速的开发C或C++的动态库,并能自动将so和Java应用一起打包成apk。

本篇知识要点:
1、NDK开发之C/C++入门
2、JNI模块开发
3、Linux编程
4、底层图片处理
5、音视频开发
6、机器学习

NDK模块开发

  • 4.6 Flutter学习进阶

2019 年无疑是 Flutter 技术如火如荼发展的一年。

每一个移动开发者都在为 Flutter 带来的“快速开发、富有表现力和灵活的 UI、原生性能”的特色和理念而痴狂,从超级 App 到独立应用,从纯 Flutter 到混合栈,开发者们在不同的场景下乐此不疲的探索和应用着 Flutter 技术,也在面临着各种各样不同的挑战。

本篇知识要点:
1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter Dart语言系统入门

Flutter学习

  • 4.7 微信小程序开发

微信小程序作为现在比较火的编程开发应用场景之一,深受市场的青睐,这让不少开发者眼馋不已。但是对于初学者来说,就完全摸不着头脑了,不知道微信小程序开发制作需要学习那些知识,有需要的朋友可以参考本篇。

本篇知识要点:
1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战

微信小程序开发

  • 4.8 Android相关源码解读
    只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

Android相关源码解读
Android相关源码解读部分内容

由于篇幅原因,以上完整学习笔记pdf如有需要,请体谅下码字不易,可以 点赞+评论 支持下我,然后点击这里免费自取!

这篇关于每日一遍,BUG再见!程序员bug修复宝典重现天日!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/671473

相关文章

《纳瓦尔宝典》是纳瓦尔·拉维坎特(Naval Ravikant)的智慧箴言

《纳瓦尔宝典》是一本由埃里克·乔根森(Erik Jorgensen)编著的书籍,该书于2022年5月10日由中信出版社出版。这本书的核心内容围绕硅谷知名天使投资人纳瓦尔·拉维坎特(Naval Ravikant)的智慧箴言,特别是关于财富积累和幸福人生的原则与方法。 晓北斗推荐 《纳瓦尔宝典》 基本信息 书名:《纳瓦尔宝典》作者:[美] 埃里克·乔根森译者:赵灿出版时间:2022

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

每日一练7:简写单词(含链接)

1.链接 简写单词_牛客题霸_牛客网 2.题目 3.代码1(错误经验) #include <iostream>#include <string>using namespace std;int main() {string s;string ret;int count = 0;while(cin >> s)for(auto a : s){if(count == 0){if( a <=

【每日刷题】Day113

【每日刷题】Day113 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 91. 解码方法 - 力扣(LeetCode) 2. LCR 098. 不同路径 - 力扣(LeetCode) 3. 63. 不同路径 II - 力扣(LeetCode) 1. 91. 解码方法 - 力扣(LeetCode) //思路:动态规划。 cl

【经验交流】修复系统事件查看器启动不能时出现的4201错误

方法1,取得『%SystemRoot%\LogFiles』文件夹和『%SystemRoot%\System32\wbem』文件夹的权限(包括这两个文件夹的所有子文件夹的权限),简单点说,就是使你当前的帐户拥有这两个文件夹以及它们的子文件夹的绝对控制权限。这是最简单的方法,不少老外说,这样一弄,倒是解决了问题。不过对我的系统,没用; 方法2,以不带网络的安全模式启动,运行命令行,输入“ne

LabVIEW程序员是怎样成长为大佬

成为一名LabVIEW编程领域的“大佬”需要时间、实践、学习和解决复杂问题的经验。尽管LabVIEW作为一种图形化编程语言在初期可能相对容易上手,但要真正成为精通者,需要在多个层面上深入理解。以下是LabVIEW程序员如何逐步成长为“大佬”的路径: 1. 打好基础 LabVIEW的大佬们通常在初期会打下非常坚实的基础,理解LabVIEW编程的核心概念,包括: 数据流编程模型:Lab

力扣 739. 每日温度【经典单调栈题目】

1. 题目 理解题意: 1.1. 给一个温度集合, 要返回一个对应长度的结果集合, 这个结果集合里面的元素 i 是 当前 i 位置的元素的下一个更高温度的元素的位置和当前 i 位置的距离之差, 若是当前元素不存在下一个更高温度的元素, 则这个位置用0代替; 2. 思路 本题用单调栈来求解;单调栈就适用于来求当前元素左边或者右边第一个比当前元素大或者小的元素;【单调栈:让栈中的元素保持单调

每日一题——第八十一题

打印如下图案: #include<stdio.h>int main() {int i, j;char ch = 'A';for (i = 1; i < 5; i++, ch++){for (j = 0; j < 5 - i; j++){printf(" ");//控制空格输出}for (j = 1; j < 2 * i; j++)//条件j < 2 * i{printf("%c", ch