还剩49页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
计算机科学入门算法与编程欢迎来到计算机科学的奇妙世界!在这个信息时代,计算机科学已成为推动社会发展的核心力量本课程将带领你探索算法与编程的基础知识,从最简单的概念开始,逐步深入到更复杂的理论和应用无论你是完全的初学者,还是已经有一些编程经验的学生,这门课程都将为你提供系统化的学习路径我们将通过理论讲解与实践案例相结合的方式,帮助你建立坚实的计算机科学基础让我们一起踏上这段充满挑战与乐趣的学习之旅吧!课程介绍计算机科学之旅启航从计算机科学的基础概念开始,理解算法与编程的重要性,以及它们在现代技术中的核心作用探索深入编程语言、算法设计和数据结构的世界,掌握解决问题的核心思维方式应用通过实际案例与练习,应用所学知识解决真实问题,培养实践能力提升探讨高级主题和职业发展路径,为未来的深入学习和实践奠定基础计算机科学是人类智慧的结晶,它改变了我们生活、工作和交流的方式这门学科融合了数学、逻辑和创造力,构建了数字时代的基础通过本课程,你将了解计算机如何思考,以及如何指导它们解决各种复杂问题算法介绍什么是算法算法定义算法特性算法是解决问题的一系列明确、好的算法应具备正确性、可行有限的指令集合每个算法必须性、效率性、简洁性和确定性五有明确的输入和输出,并且能够大特性,确保能够准确且高效地在有限时间内完成任务解决问题算法应用从导航系统到推荐引擎,从搜索引擎到自动驾驶,算法已成为现代技术的核心,无处不在地影响着我们的日常生活算法可以看作是解决问题的食谱,就像烹饪步骤一样,指导我们从原材料(输入数据)一步步加工,最终得到期望的成品(输出结果)优秀的算法能够以最少的资源(时间和空间)达成目标,这也是计算机科学追求的核心目标之一编程入门基本概念变量与常量变量是程序中用于存储数据的命名容器,可以根据需要更改其值;而常量一旦定义,其值在程序执行过程中不能被修改数据类型数据类型定义了变量可以存储的数据种类,如整数、浮点数、字符、布尔值等,不同编程语言支持的数据类型可能有所不同控制结构控制结构决定了程序的执行流程,主要包括顺序结构、选择结构(如if-else)和循环结构(如for、while循环)函数与方法函数是执行特定任务的代码块,可以接收输入参数并返回结果,有助于代码重用和模块化设计学习编程就像学习一门新的语言,我们需要掌握其词汇(变量、数据类型)和语法(控制结构、函数)通过组合这些基本元素,我们可以创建出从简单计算器到复杂网站的各种应用编程的魅力在于,通过有限的基础概念,我们可以构建无限的可能性编程语言首选语言及特点Python Java以简洁易读的语法著称,拥有丰富的库和框架,适合初学者入门,一次编写,到处运行的跨平台特性,拥有强大的企业级支持,常广泛应用于数据科学、人工智能和Web开发等领域用于Android应用开发、企业级应用和大型系统JavaScript C/C++Web开发的核心语言,支持前端交互和后端开发(Node.js),具执行效率高,内存控制能力强,广泛用于系统编程、游戏开发和嵌有灵活的函数式编程特性,生态系统活跃入式系统,但学习曲线较陡峭选择第一门编程语言时,应考虑学习目标、应用领域和个人偏好对初学者而言,Python通常是不错的选择,因为它的语法简洁明了,学习资源丰富随着经验积累,可以根据需要学习其他语言,因为编程的核心思想在不同语言间是相通的算法思想分治法与贪心算法分治法贪心算法分治法(Divide andConquer)的核心思想是将一个复杂问题贪心算法(Greedy Algorithm)在每一步选择中都采取当前状分解为若干个规模较小但类似的子问题,解决这些子问题,然后态下最优的选择,以期望通过局部最优解得到全局最优解将结果合并得到原问题的解•典型算法Huffman编码、Dijkstra算法•典型算法归并排序、快速排序•优势实现简单,效率高•优势可以有效处理规模大的问题•局限性不一定能得到全局最优解•应用场景排序、搜索、矩阵乘法等分治法和贪心算法代表了两种不同的解决问题思路分治法通过分而治之的方式处理复杂问题,适合可以明确分解的任务;而贪心算法则追求当下最优,适合一些局部最优能导致全局最优的特殊问题理解这些基本算法思想,对于培养程序设计能力和问题解决能力至关重要数据结构数组和链表链表特点•非连续内存空间存储数组特点•不支持随机访问(需要从头遍历)•连续内存空间存储•插入删除操作效率高(O1时间复•支持随机访问(O1时间复杂度)杂度)•插入删除操作效率低(需要移动元•长度可动态调整素)适用场景•长度通常固定(某些语言中可动态调整)数组适合元素数量固定且需要频繁随机访问的场景;链表适合元素数量变化频繁、主要进行插入删除操作的场景数组和链表是两种最基础也最常用的数据结构,它们各有优缺点选择使用哪种数据结构,应根据具体应用场景的需求来决定理解这些基本数据结构的特性,是掌握更复杂数据结构和算法的基础在实际编程中,我们经常需要权衡时间效率和空间效率,做出最适合当前问题的选择数据结构栈与队列栈()队列()Stack Queue栈是一种遵循后进先出(LIFO LastIn FirstOut)原则的线队列是一种遵循先进先出(FIFO FirstIn FirstOut)原则的性数据结构线性数据结构•基本操作入栈(push)和出栈(pop)•基本操作入队(enqueue)和出队(dequeue)•只能在一端(栈顶)进行操作•在一端(队尾)添加元素,从另一端(队首)移除元素•应用场景函数调用栈、表达式求值、括号匹配检查等•应用场景任务调度、消息传递、广度优先搜索等栈和队列虽然结构简单,但在计算机科学中有着广泛的应用它们可以基于数组或链表实现,根据具体需求选择实现方式理解栈和队列的工作原理,对于理解许多算法和系统设计具有重要意义例如,操作系统中的进程调度、编译器中的语法分析等,都大量使用了这两种数据结构数据结构树与图树()图()Tree Graph•非线性数据结构,具有层次关系•由节点(顶点)和边组成的非线性结构•每个节点有零个或多个子节点•没有环路,只有一个根节点•可以有环路,无固定层次•分为有向图和无向图•典型类型二叉树、AVL树、红黑树等•可以带权重(加权图)•应用文件系统、组织结构、决策树•应用社交网络、地图导航、网络路由树与图的关系树是一种特殊的图,即无环连通图树总是连通的,而图可以是非连通的;树没有环路,而图可以有环路树和图是计算机科学中最强大的数据结构之一,能够表示各种复杂的关系和结构它们在算法设计、人工智能、数据库系统等领域有着广泛应用理解树和图的基本概念和操作,是进阶学习计算机科学的重要基础现代软件系统中,许多复杂问题的解决方案都依赖于树和图的灵活应用算法复杂度时间复杂度与空间复杂度O1On常数复杂度线性复杂度执行时间与输入规模无关,如数组的随机访问执行时间与输入规模成正比,如简单遍历On²Olog n平方复杂度对数复杂度如嵌套循环,冒泡排序等如二分查找,效率较高算法复杂度分析是评估算法效率的重要工具,帮助我们理解算法在面对大规模数据时的表现时间复杂度关注算法执行所需的时间,通常用大O表示法(Big ONotation)来描述算法运行时间与输入规模之间的关系空间复杂度则关注算法执行所需的内存空间在实际应用中,我们通常需要在时间复杂度和空间复杂度之间做权衡随着数据规模的增长,低复杂度算法的优势会越来越明显理解复杂度分析,是选择和优化算法的关键能力递归与迭代基本原理与应用递归()迭代()Recursion Iteration递归是一种解决问题的方法,其中迭代通过循环结构重复执行代码函数调用自身来解决更小规模的相块,直到满足特定条件不涉及函同问题递归需要基准情况(终止数自身调用,通常使用循环控制条件)来防止无限递归适合用于(如for、while)来实现适合具有自相似结构的问题,如树遍线性问题,如数组处理、简单计算历、汉诺塔问题等等比较与选择递归代码通常更简洁易读,但可能导致栈溢出和性能低下;迭代通常更高效,但代码可能更复杂选择取决于问题特性、性能需求和可读性考虑递归和迭代是两种不同的程序控制结构,它们都能用来处理重复性任务,但适用场景和实现方式不同理解何时使用递归,何时使用迭代,对于算法设计和问题解决至关重要在某些情况下,递归解法可以通过尾递归优化或记忆化搜索技术来提高效率,使其性能接近甚至超过迭代解法编程范式命令式编程基本概念命令式编程(Imperative Programming)是最古老也最常见的编程范式,它关注如何做,通过一系列指令明确告诉计算机执行的具体步骤程序的状态通过变量改变来体现,控制流通过条件判断和循环结构实现历史发展命令式编程可追溯到最早的计算机语言,如FORTRAN(1957年)和COBOL(1959年)这些语言的设计直接反映了计算机硬件的工作方式,使程序员能够精确控制计算机的操作随着时间发展,C、Pascal等语言进一步完善了命令式编程的特性核心特点命令式编程以语句为中心,通过赋值语句改变程序状态,使用控制结构(条件语句、循环语句)控制执行流程典型的命令式语言包括C、Pascal、Python等命令式编程强调做什么和怎么做,程序员需要详细指定每一步操作命令式编程是最接近人类思考问题方式的编程范式,也是大多数编程初学者首先接触的范式它直观易懂,对硬件资源的控制也更直接然而,随着软件系统规模和复杂度的增加,纯粹的命令式编程可能导致代码难以维护和扩展,这促使了其他编程范式的发展编程范式函数式编程纯函数相同输入产生相同输出,无副作用不可变性数据创建后不可修改,保证程序稳定性高阶函数3函数可作为参数传递或作为返回值声明式编程关注做什么而非怎么做函数式编程(Functional Programming)是一种将计算过程视为数学函数求值的编程范式它强调函数的应用,而非状态的改变典型的函数式编程语言包括Haskell、Lisp、Erlang等,而JavaScript、Python、Scala等语言也支持函数式编程风格函数式编程的优势在于代码简洁、可测试性强、并发安全,特别适合处理复杂的数据转换和并行计算随着现代软件系统对并发处理需求的增加,函数式编程正获得越来越多的关注和应用编程范式面向对象编程对象类继承对象是数据和行为的封类是对象的模板或蓝继承允许一个类(子装,是面向对象程序的图,定义了一组对象共类)获取另一个类(父基本构建单元对象通有的属性和方法对象类)的属性和方法,促过属性存储状态,通过是类的实例,通过实例进代码重用和建立类层方法定义行为化类来创建次关系多态多态使不同类的对象对同一消息作出响应,每个对象根据自身类定义的方式执行操作,增强了代码的灵活性面向对象编程(Object-Oriented Programming,OOP)是一种将现实世界问题建模为对象及其交互的编程范式它的核心思想是将数据和操作数据的方法绑定成一个整体,形成对象,从而更好地模拟现实世界的问题流行的面向对象编程语言包括Java、C++、Python、Ruby等面向对象编程的优势在于模块化、可重用性强、易于维护和扩展,特别适合大型软件系统的开发面向对象设计原则单一职责原则原则定义优势一个类应该只有一个引起它变化的原因换提高类的可读性、可维护性和可重用性;降言之,一个类应该只有一个职责,只负责一低类的复杂度;减少变更带来的影响范围项功能应用平衡实现方法过度应用可能导致类爆炸和系统过于碎片识别并分离类的不同职责;确保每个类的方化;需要在职责单一和系统复杂度之间找到法和属性都服务于其单一职责;在需要时创平衡点建新类来承担分离出的职责单一职责原则(Single ResponsibilityPrinciple,SRP)是面向对象设计的五大原则(SOLID)之一,由Robert C.Martin(Uncle Bob)提出它强调每个类应该只有一个职责,这有助于创建更为内聚、耦合度低的系统在实际应用中,识别和定义职责是应用该原则的关键挑战一般来说,如果一个类的方法可以根据不同的目的或关注点分组,那么这个类可能违反了单一职责原则,应考虑重构面向对象设计原则开闭原则开放性对扩展开放,鼓励添加新功能封闭性对修改封闭,保护现有功能抽象接口通过抽象接口支持扩展开闭原则(Open/Closed Principle,OCP)是面向对象设计的核心原则之一,由Bertrand Meyer在1988年提出它强调软件实体(类、模块、函数等)应该对扩展开放,对修改关闭这意味着当需要添加新功能时,应该通过扩展现有代码(如添加新类)而不是修改现有代码来实现开闭原则的实现通常依赖于抽象和多态通过定义稳定的抽象接口,系统可以在不改变核心代码的情况下接纳新的具体实现这种设计方式有助于提高系统的可维护性和可扩展性,减少引入错误的风险,特别适合需要频繁添加新功能的系统算法案例排序算法(冒泡排序)算法原理冒泡排序通过重复遍历要排序的序列,比较相邻元素并交换位置(如果顺序错误),使较大元素逐渐浮向序列末端,就像气泡上升一样每次遍历后,最大的元素会移动到正确位置实现步骤•从序列起始位置开始,比较相邻的两个元素•如果前者大于后者,交换它们的位置•向后移动一位,继续比较下一对相邻元素•一轮遍历完成后,最大元素已位于序列末端•重复上述步骤,每次排除已确定位置的元素性能分析时间复杂度最好情况On,平均和最坏情况On²;空间复杂度O1,仅需常数级额外空间冒泡排序简单直观,但对于大规模数据效率较低,适合小数据集或教学目的冒泡排序是最简单的排序算法之一,也是初学者接触的第一个排序算法尽管它在实际应用中因效率问题较少使用,但学习冒泡排序有助于理解排序算法的基本概念和评估方法通过优化(如引入标志位提前终止已排序序列的遍历),可以略微提高冒泡排序的效率算法案例排序算法(快速排序)基准选择从数组中选择一个元素作为基准(pivot)常见选择方法包括选第一个元素、最后一个元素、中间元素或随机元素基准选择对算法性能有显著影响分区过程将数组重新排列,所有小于基准的元素移到基准左侧,所有大于基准的元素移到基准右侧完成后,基准元素位于其最终排序位置递归排序递归地对基准左右两侧的子数组应用相同的排序过程,直到所有子数组长度为0或1(即已排序)递归是快速排序的核心机制快速排序是一种高效的排序算法,采用分治策略,平均时间复杂度为On logn它的原地排序特性(空间复杂度Olog n,仅用于递归调用栈)使其在实际应用中非常受欢迎许多编程语言的标准库排序函数都使用快速排序或其变种快速排序的性能受基准选择影响很大在最坏情况下(如已排序数组,每次选择最小或最大元素作基准),时间复杂度可退化为On²通过随机选择基准或使用三数取中法可有效避免这种情况算法案例查找算法(线性查找与二分查找)线性查找()二分查找()Linear SearchBinary Search线性查找是最简单的查找算法,它从序列的一端开始,逐个检查二分查找利用有序序列的特性,通过将搜索区间反复折半,快速每个元素,直到找到目标元素或遍历完整个序列缩小目标元素可能存在的范围•时间复杂度On•时间复杂度Olog n•空间复杂度O1•空间复杂度O1(迭代)或Olog n(递归)•优点适用于有序或无序序列•优点效率高,特别适合大规模数据•缺点对于大规模数据效率低•缺点仅适用于有序序列线性查找和二分查找的效率差异在数据量增加时越发明显例如,对于包含一百万个元素的有序数组,线性查找最坏情况需要一百万次比较,而二分查找最多只需要约20次比较(log₂1,000,000≈20)在实际应用中,需要根据数据特性(有序性、数据规模)和查找频率来选择合适的查找算法对于频繁查找的大规模有序数据,值得投入前期排序成本以便后续使用二分查找;对于小规模或不常查找的数据,简单的线性查找可能更合适编程实践初学者如何选择项目为初学者选择合适的编程项目至关重要,它应该既有挑战性又不至于令人气馁理想的初学者项目应该有明确的目标、适中的复杂度,并能应用所学的基础知识从简单的计算器、待办事项应用、简易网站到小游戏如井字棋,这些项目都是很好的起点最重要的是选择你感兴趣的项目兴趣是最好的老师,它能帮助你在遇到困难时保持动力同时,尝试不同类型的项目可以拓宽你的技能范围,发现自己的兴趣所在记住,完成一个简单项目比半途而废一个复杂项目更有价值循序渐进,逐步提高挑战难度,是成长为优秀程序员的正确路径编程实践如何轻松地在网上学习算法在线课程平台利用Coursera、edX、Udemy等平台提供的结构化课程,系统学习算法知识这些课程通常由知名大学或行业专家讲授,内容全面且深入浅出算法练习网站在LeetCode、HackerRank、CodeForces等平台上实践所学知识,通过解决不同难度的算法问题提升编程能力这些平台提供即时反馈和优化建议,帮助你持续进步学习社区与论坛加入Stack Overflow、GitHub、Reddit等社区,向他人学习并分享自己的知识与志同道合的学习者交流,讨论解题思路和学习方法,获取多角度的见解算法可视化工具使用VisuAlgo、Algorithm Visualizer等工具,直观理解算法的工作原理可视化展示使抽象的算法概念变得具体可感,特别适合视觉学习者高效学习算法的关键在于理论与实践相结合首先理解算法的基本原理,然后通过编码实现加深理解,最后解决实际问题巩固知识保持学习的连续性和规律性,避免长时间中断导致遗忘设定明确的学习目标,将大目标分解为小里程碑,逐步实现进步算法挑战常见问题及解决思路理解问题仔细分析问题描述,确保完全理解问题的要求和约束条件识别输入、输出和边界情况如有疑问,提出澄清性问题或进行假设并验证这一步是解决问题的基础,不可忽视设计算法思考解决问题的策略,可以从暴力解法开始,逐步优化考虑是否可以应用已知的算法模式(如分治、动态规划、贪心等)绘制流程图或伪代码有助于理清思路不要急于编码,先确保算法正确编写代码根据设计的算法编写清晰、简洁的代码遵循良好的编程实践,如有意义的变量命名、适当的注释等编写过程中要考虑代码的可读性和可维护性,便于后续修改和调试测试优化使用多种测试用例验证算法,包括正常情况、边界情况和极端情况分析时间和空间复杂度,寻找优化机会反思解决过程,总结经验教训,为解决类似问题积累经验面对算法挑战时,保持冷静和系统性思考至关重要不要被问题的复杂性吓倒,尝试将其分解为更小、更容易管理的子问题利用数据结构和算法的基础知识,寻找问题与已知解决方案之间的联系记住,解决算法问题是一项需要练习的技能,随着经验的积累,你的解题能力将不断提高贪心算法实例活动选择问题动态规划实例背包问题01物品重量价值物品126物品2210物品3312物品413物品551801背包问题是动态规划的经典问题给定n个物品,每个物品有重量和价值两个属性,背包有一个最大重量限制W目标是选择一些物品放入背包,使得总重量不超过W,同时总价值最大01表示每个物品只能选择放或不放(即0或1个)动态规划解法的核心是构建一个二维数组dp[i][j],表示考虑前i个物品,背包容量为j时能获得的最大价值状态转移方程为dp[i][j]=maxdp[i-1][j],dp[i-1][j-w[i]]+v[i],其中w[i]和v[i]分别是第i个物品的重量和价值这个方程反映了对每个物品的选择不放入背包或放入背包取较大值通过填充这个二维表格,我们最终可以得到在给定约束下的最优解动态规划实例最长公共子序列问题定义动态规划解法最长公共子序列(LCS)问题给定两个字符串,找出它们的最构建一个二维数组dp[i][j],表示字符串1的前i个字符与字符串2长公共子序列的长度子序列是从原序列中删除某些元素(可以的前j个字符的最长公共子序列长度不连续)而不改变剩余元素相对位置得到的新序列状态转移方程例如,字符串ABCBDAB和BDCABA的最长公共子序列是•若字符串1的第i个字符等于字符串2的第j个字符dp[i][j]=BCBA,长度为4dp[i-1][j-1]+1•否则dp[i][j]=maxdp[i-1][j],dp[i][j-1]LCS问题展示了动态规划的典型特征最优子结构(问题的最优解包含子问题的最优解)和重叠子问题(子问题被重复计算)通过动态规划,我们避免了递归解法中的重复计算,大大提高了效率LCS有许多实际应用,如DNA序列分析、文件差异比较、拼写检查等它也是其他动态规划问题的基础,如最长递增子序列、编辑距离等理解LCS的解法有助于掌握动态规划的核心思想和技巧编程技巧如何有效地调试代码理解错误信息仔细阅读错误消息,它们通常提供了错误的位置和性质学会解读堆栈跟踪(stack trace),识别错误发生的具体行数和调用路径不要忽视警告信息,它们往往是潜在问题的预警使用调试工具熟练使用集成开发环境(IDE)的调试功能,如断点设置、单步执行、变量监视等充分利用日志输出,在关键点插入打印语句查看变量状态使用专业调试工具如GDB、Chrome DevTools等深入分析复杂问题调试策略采用二分法定位错误将代码分成几部分,逐一排除直到找到问题区域创建最小复现示例,简化问题场景以便更容易发现根本原因进行回归测试,确保修复不会引入新问题思维方法保持耐心和系统性思考,避免匆忙下结论尝试向他人(或橡皮鸭)解释问题,这往往能启发新的思路学会使用搜索引擎查找类似问题的解决方案,但要理解原理而非盲目复制调试是编程工作中不可避免的一部分,高效的调试能力可以大大提高开发效率记住,最好的调试策略是预防bug的产生编写清晰、模块化的代码,进行单元测试,以及定期代码审查养成良好的编码习惯和文档记录习惯,可以减少调试的需求代码优化提高代码效率的方法内存管理算法优化优化内存使用,避免不必要的大对象创建,选择合适的算法和数据结构,降低时间复杂1减少垃圾回收压力在适当场景使用对象度例如,将On²的算法优化为On logn池、缓存等技术重用对象,降低内存分配开或On,对于大数据量处理效果显著销并发处理数据库优化4利用多线程、异步编程处理I/O密集型任优化SQL查询,添加适当索引,减少查询次务使用线程池管理线程资源,避免过度创数使用批处理替代频繁的单条操作,考虑建线程导致的上下文切换开销数据库缓存和连接池降低资源消耗代码优化应遵循过早优化是万恶之源的原则,先确保代码正确可维护,再有针对性地优化性能瓶颈使用性能分析工具(如Profiler)定位真正的性能瓶颈,避免主观猜测优化时应权衡代码可读性和性能提升,不要为了微小的性能改进而牺牲代码质量特别注意避免常见的性能陷阱如在循环中进行字符串拼接、重复计算不变的值、频繁创建临时对象等掌握编程语言和框架的性能特性,了解编译器和运行时的优化机制,可以编写更高效的代码学习建议如何建立良好的学习习惯制定明确目标建立学习系统•设定短期、中期和长期学习目标•创建固定的学习时间和空间•目标应具体、可衡量、可实现•使用番茄工作法等时间管理技术•将大目标分解为小任务,逐步完成•构建知识体系,串联零散知识点•定期回顾和调整目标•定期复习,防止遗忘实践与反思•通过编码实践巩固理论知识•参与实际项目,应用所学解决问题•反思学习过程,总结经验教训•寻求反馈,持续改进学习方法良好的学习习惯不是一蹴而就的,需要持续的努力和调整保持积极的学习态度,相信成长思维而非固定思维,接受挑战和失败是学习过程的一部分培养好奇心和批判性思维,不仅学习是什么,还要探究为什么和如何应用学习编程和算法尤其需要耐心和毅力遇到困难时,尝试换个角度思考,或暂时放下转而学习其他内容,让潜意识有时间处理复杂问题建立学习社区和网络,与志同道合的人交流分享,不仅能获取新知识,还能保持学习动力算法思维如何养成算法思维问题分解学会将复杂问题分解为更小、更易管理的子问题模式识别2培养识别问题中常见模式的能力抽象思维聚焦问题核心,忽略无关细节逻辑推理基于已知条件推导出合理结论算法思维是一种结构化解决问题的方法,它不仅适用于编程,也适用于日常生活中的决策和问题解决培养算法思维需要刻意练习和持续学习,通过解决各种算法问题,分析不同解决方案的优缺点,逐渐形成系统化思考的习惯阅读优秀的算法书籍和论文,研究经典算法的设计思想,对培养算法思维很有帮助参与算法竞赛或编程挑战也是锻炼算法思维的好方法在实践中,尝试用不同方法解决同一问题,分析比较各种算法的效率和适用场景,能够深化对算法思想的理解记住,算法思维不是天生的,而是通过学习和实践培养起来的能力编程社区如何参与开源项目寻找合适项目根据个人兴趣和技能水平选择合适的开源项目GitHub Explore、First TimersOnly等平台可以帮助发现适合初学者的项目查找标记为good firstissue或beginnerfriendly的任务作为入门了解项目阅读项目文档,理解项目目标、架构和贡献指南研究项目的代码约定、提交流程和社区规范尝试构建和运行项目,熟悉其功能和工作方式沟通参与在开始贡献前,通过邮件列表、论坛或聊天频道与社区成员交流讨论你想解决的问题或实现的功能,获取反馈和建议清晰表达你的想法和计划,尊重社区共识提交贡献从小处着手,如修复拼写错误或简单bug遵循项目的提交规范,提供清晰的提交信息耐心等待代码审查,积极响应反馈并做出必要修改参与开源项目不仅能提升技术能力,还能扩展人脉、建立声誉并获得实际项目经验开源贡献形式多样,除了代码贡献外,还可以参与文档编写、翻译、回答问题、报告bug等持续参与同一项目,逐渐深入了解项目核心,可以承担更复杂的任务和更大的责任工程师的职业发展算法与编程在职业中的应用技术领导力架构设计与团队指导1专业技术能力深度技术专长与系统优化项目实践经验解决实际问题与工程实践算法与编程基础4核心概念与基础技能在技术职业发展中,算法和编程能力是基础,但随着职业阶段的推进,其重要性和应用方式会发生变化初级阶段,扎实的算法和编程基础帮助工程师高效实现需求;中级阶段,这些能力使工程师能够解决复杂问题,优化系统性能;高级阶段,算法思维则用于系统架构设计和技术策略制定不同行业和岗位对算法能力的要求也各不相同搜索引擎、推荐系统、量化交易等领域对算法要求极高;而企业应用开发可能更注重业务理解和系统集成能力全面发展技术技能的同时,也要培养沟通、协作、项目管理等软技能,以及对业务领域的深入理解,这样才能在职业生涯中获得长期成功从初学者到专家算法学习之路入门阶段•掌握基础数据结构(数组、链表、栈、队列)•学习基本算法(排序、查找)•理解算法复杂度分析•解决简单算法题目(如LeetCode简单难度)进阶阶段2•深入理解高级数据结构(树、图、散列表)•掌握常见算法范式(分治、动态规划、贪心)•学习典型算法问题的解决方案•能够解决中等难度算法题目高级阶段•研究复杂算法和数据结构•学习特定领域的算法(如机器学习、密码学)•能够设计新算法解决非标准问题•解决高难度算法竞赛题目专家阶段•深入研究算法理论和前沿发展•能够创新算法并发表研究成果•解决行业内复杂技术挑战•指导他人学习和应用算法算法学习是一个循序渐进的过程,需要理论学习与实践练习相结合建议初学者从基础数据结构和简单算法开始,打好基础后再逐步挑战更复杂的内容定期参与算法竞赛或挑战可以检验学习成果并发现不足算法基础位运算与二进制运算⁰2基本概念位(二进制位)是计算机存储的最小单位2¹位运算符包括与、或|、异或^、非~、左移、右移2²应用场景加密算法、图形处理、优化计算等2³效率优势直接操作二进制位,效率高位运算是直接对二进制位进行操作的运算,它们在执行效率上往往优于普通的算术运算例如,左移一位等同于乘以2,右移一位等同于除以2,但执行速度更快位运算在需要优化性能的场景,如游戏开发、图像处理、加密算法中应用广泛掌握位运算需要对二进制表示有深入理解,以及熟悉各种位操作的效果一些经典的位运算技巧包括使用异或交换两个变量的值(无需额外空间)、使用位掩码设置或清除特定位、利用与运算判断数字奇偶性等这些技巧不仅能提高程序效率,还能展示程序员对底层计算机原理的理解高级数据结构散列表与堆散列表()堆()Hash TableHeap散列表是一种基于键值对存储数据的结构,通过散列函数将键映射堆是一种特殊的基于树的结构,通常用完全二叉树实现,满足堆属到数组索引,实现快速查找、插入和删除操作性每个节点的值都大于或等于(最大堆)或小于或等于(最小堆)其子节点的值•平均时间复杂度O1•核心组件散列函数、冲突解决策略•操作时间复杂度插入Olog n、删除最大/最小元素Olog n•特点顶部总是最大值(最大堆)或最小值(最小堆)•常见冲突解决方法链式法、开放寻址法•实现方式通常使用数组表示•应用数据库索引、缓存系统、符号表•应用优先队列、堆排序、图算法(如Dijkstra算法)散列表和堆是高级数据结构的典型代表,它们在各自适用场景中能提供极高的性能散列表的主要优势在于平均O1时间复杂度的查找操作,使其成为需要快速查询的应用首选而堆则在需要频繁获取最大或最小元素的场景中表现出色,如优先级队列的实现理解这些数据结构的内部工作原理及其性能特点,对于设计高效算法至关重要在实际应用中,我们常常需要根据具体需求在时间复杂度、空间复杂度和实现复杂度之间做出权衡,选择最适合当前问题的数据结构高级数据结构优先队列与树Trie优先队列()树(前缀树字典树)Priority QueueTrie/•定义一种特殊的队列,元素出队顺序基于优•定义一种树形数据结构,用于高效存储和检先级而非入队顺序索字符串集合•实现通常基于堆(二叉堆)实现•特点所有子节点都共享相同前缀的节点•操作插入Olog n、获取/删除最高优先级元•操作插入、查找、前缀匹配均为Om,m素Olog n为字符串长度•应用任务调度、事件驱动模拟、Dijkstra算•应用自动补全、拼写检查、IP路由、字符串法等集合查找实例应用优先队列在操作系统任务调度中应用广泛,高优先级任务先执行;而Trie树在搜索引擎的查询推荐和输入法的联想功能中发挥重要作用,能快速找到所有具有特定前缀的词优先队列和Trie树是解决特定问题的强大工具优先队列适合需要按优先级处理元素的场景,如模拟系统中的事件处理、图算法中的节点选择等它的核心优势在于能够在保持元素顺序的同时,高效地进行插入和删除最高优先级元素的操作Trie树则特别适合处理字符串集合,尤其是需要前缀匹配的场景与散列表相比,Trie树不仅能快速查找完整字符串,还能轻松找出所有共享特定前缀的字符串,这在自动补全功能中非常有用理解这些高级数据结构及其应用场景,有助于在实际编程中选择最优的解决方案高级算法字符串匹配算法(算法)KMP问题背景在文本串中查找模式串的所有出现位置,朴素算法需要Onm时间复杂度,而KMP算法通过预处理模式串,实现On+m的时间复杂度预处理计算模式串的部分匹配表(next数组),记录每个位置的最长相等前后缀长度,用于在匹配失败时的快速跳转匹配过程从文本串开始位置逐一比较,当不匹配时,根据部分匹配表跳过不必要的比较,避免回溯文本串指针效率提升通过重用已知信息,KMP算法在长文本和复杂模式中显著优于朴素算法,特别适合大规模文本搜索KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,由Donald Knuth、James H.Morris和VaughanPratt在1977年共同发表它的核心思想是利用模式串本身的信息,在匹配失败时避免不必要的回溯,从而提高匹配效率KMP算法的关键在于构建部分匹配表(next数组),这个过程本身就是一个模式串与自身的匹配过程虽然KMP算法实现较为复杂,需要理解前缀、后缀和失败函数等概念,但它的高效性使其成为文本编辑器、生物信息学DNA序列匹配等领域的重要工具理解KMP算法不仅有助于解决字符串匹配问题,还能帮助掌握其他高级算法的设计思想高级算法最小生成树算法(算法与算法)Prim Kruskal算法算法Prim KruskalPrim算法采用贪心策略,从一个起始顶点开始,逐步扩展生成树Kruskal算法也采用贪心策略,但关注的是边的选择而非顶点的扩展•算法步骤始于任意顶点,每次选择连接树与非树顶点的最小权重•算法步骤将所有边按权重排序,依次选择不形成环的最小权重边边•时间复杂度OE logE,主要受边排序影响•时间复杂度使用二叉堆实现为OE logV,E为边数,V为顶点数•适用场景稀疏图(边数远小于顶点数的平方)•适用场景稠密图(边数接近顶点数的平方)•特点使用并查集检测环,关注边的添加顺序•特点关注点的加入顺序,维护已纳入树的顶点集合最小生成树(Minimum SpanningTree,MST)是连接图中所有顶点的树,其边的权重总和最小它在网络设计、电路布线、集群分析等领域有广泛应用Prim和Kruskal算法是解决MST问题的两种经典方法,都基于贪心策略,但实现思路不同选择使用哪种算法通常取决于图的特性对于边较多的稠密图,Prim算法通常更高效;对于边较少的稀疏图,Kruskal算法可能更合适两种算法的理解和实现难度相当,都是算法设计中贪心策略的典型应用掌握这两种算法有助于理解更复杂的图算法,如最短路径算法和网络流算法分布式算法基本概念与实例共识算法时钟同步容错机制分布式数据处理解决分布式系统中多节点达成协调分布式系统中各节点的时使系统在部分组件失效时仍能高效处理分布在多节点的大规一致的问题,如Paxos、Raft间观念,如NTP(网络时间协提供服务,如副本复制算法、模数据,如MapReduce、和区块链中的PoW(工作量证议)和逻辑时钟算法时钟同故障检测和恢复机制这些算Spark等计算框架使用的并行明)这些算法确保即使在部步对于事件顺序确定、分布式法增强了分布式系统的可靠性算法这些算法通过数据分片分节点故障或网络不稳定的情事务和一致性维护至关重要和可用性,是现代云服务的基和并行处理提高了大数据处理况下,系统仍能正常运行础的效率分布式算法是设计和实现分布式系统的核心,它们解决了传统集中式算法无法应对的挑战,如网络延迟、节点故障和数据一致性问题与集中式算法相比,分布式算法需要考虑更多因素,如网络拓扑、通信成本、故障模型等分布式算法在现代技术基础设施中应用广泛,从云计算、大数据处理到区块链和物联网理解这些算法的原理和应用场景,对于设计可靠、高效的分布式系统至关重要随着分布式系统规模的不断扩大,新型分布式算法也在不断涌现,以应对更复杂的挑战并行计算利用多核处理器加速计算线程与进程并行算法设计进程是独立的执行单元,拥有独立的内存空间;并行算法需要考虑任务分解、负载均衡、数据依线程是进程内的执行路径,共享所属进程的资赖和同步等因素好的并行算法能够最小化线程源多线程编程是实现并行计算的常用方法,能间的通信和同步开销,最大化并行度,从而获得够充分利用多核处理器的计算能力接近线性的加速比多核架构并行编程框架现代处理器通常包含多个核心,每个核心可以独OpenMP、MPI、CUDA等框架简化了并行程序立执行指令多核架构使得同时执行多个任务或的开发这些框架提供了高级抽象和工具,使程将单个任务分解并行处理成为可能,从而提高整序员能够专注于算法逻辑而非底层并行细节,提体计算效率高开发效率3并行计算通过同时执行多个计算任务,显著提高了程序的执行效率,特别适合处理大规模数据分析、科学模拟、图像处理等计算密集型任务随着摩尔定律的放缓,增加核心数量已成为提升处理器性能的主要方式,这使得并行编程技能变得愈发重要成功实现并行计算面临多种挑战,如数据竞争、死锁、同步开销等掌握并行编程模式(如分治、管道、主从等)和性能优化技术,对于充分发挥多核处理器的潜力至关重要随着人工智能、大数据等领域的发展,并行计算的应用前景更加广阔算法安全基本安全原则与网络攻击防御加密算法保护数据机密性的核心技术,包括对称加密(如AES、DES)和非对称加密(如RSA、ECC)加密算法通过复杂的数学变换将明文转换为密文,确保只有授权方能访问信息内容哈希算法验证数据完整性的重要工具,如SHA-
256、MD5等哈希算法生成数据的固定长度指纹,任何细微改变都会导致哈希值显著不同,用于检测数据篡改入侵检测算法识别网络攻击的关键机制,基于规则匹配、统计分析或机器学习方法这些算法通过分析网络流量模式,识别异常行为和潜在威胁,提前预警或拦截攻击认证与授权算法控制系统访问的基础,包括密码哈希存储、多因素认证、OAuth等协议这些机制确保只有合法用户能够访问系统资源,并根据权限级别控制操作范围算法安全是现代网络安全的基石,它关注如何设计和应用算法来保护系统和数据免受攻击安全算法需要满足多种要求,如计算难度(攻击者难以破解)、可证明安全性(基于数学证明)和效率(不过度消耗资源)等随着量子计算的发展,量子抗性算法也成为研究热点除了技术层面,算法安全还需考虑实现和应用层面的风险即使最强大的算法,如果实现不当或应用不正确,也可能存在漏洞因此,遵循安全编码实践、定期更新和审计、采用深度防御策略等原则同样重要在日益复杂的网络环境中,全面的安全策略需要将算法安全与其他安全措施有机结合算法与机器学习基础概念与应用场景监督学习无监督学习使用标记数据训练模型,包括分类和回归任务从无标记数据中发现模式,主要包括聚类和降1常见算法有线性回归、决策树、支持向量机、神维常见算法有K均值聚类、层次聚类、主成分分2经网络等析等深度学习强化学习使用多层神经网络处理复杂数据,常见架构有卷智能体通过与环境交互学习最优决策策略代表积神经网络、循环神经网络、变换器等算法包括Q学习、策略梯度、深度Q网络等机器学习是算法的高级应用,它使计算机能够从数据中学习并改进性能,而无需显式编程机器学习算法通常分为训练阶段(从数据中学习模型参数)和推理阶段(使用学习的模型进行预测)这些算法的核心是优化问题,目标是最小化预测误差或最大化某种性能指标机器学习在现代社会有广泛应用推荐系统帮助我们发现感兴趣的内容;计算机视觉使设备能够看见世界;自然语言处理实现人机对话;异常检测识别欺诈行为等随着数据量增加和算力提升,机器学习算法的能力也在不断增强,为各行各业带来革命性变化理解这些算法的原理和应用对于把握人工智能时代的机遇至关重要算法应用自然语言处理中的常见算法文本分类算法序列标注算法•朴素贝叶斯基于贝叶斯定理的简单分类•隐马尔可夫模型基于概率状态转移的序列器,广泛用于垃圾邮件过滤、情感分析标注•支持向量机寻找最优超平面分隔不同类别•条件随机场考虑上下文信息的概率图模型的文本•BiLSTM-CRF结合深度学习和概率模型的•深度学习模型如BERT、GPT等,能捕捉文混合架构本深层语义,适用于复杂分类任务•应用命名实体识别、词性标注、分词等语言模型与生成算法•n-gram模型基于前n-1个词预测下一个词•RNN/LSTM捕捉长距离依赖的循环神经网络•Transformer基于自注意力机制的并行架构•应用文本生成、机器翻译、对话系统等自然语言处理(NLP)是人工智能的重要分支,致力于让计算机理解和生成人类语言NLP算法面临多种挑战,包括语言的歧义性、上下文依赖、文化差异等近年来,深度学习特别是预训练语言模型的发展极大推动了NLP技术的进步,实现了许多过去难以想象的应用这些算法的应用十分广泛搜索引擎理解查询意图并返回相关结果;智能助手能够回答问题和执行指令;自动摘要工具提取文档关键信息;情感分析系统理解用户反馈情绪;机器翻译系统打破语言障碍随着算法的不断进步,NLP技术正在改变人类与计算机交互的方式,并为信息获取和知识处理带来革命性变化算法应用计算机视觉中的基本算法图像分类物体检测图像分割图像分类算法将整个图像分配到预定义的类别中物体检测算法不仅识别图像中的物体类别,还定位图像分割算法将图像划分为多个有意义的区域,包卷积神经网络(CNN)如AlexNet、ResNet、其位置(通常用边界框表示)主流算法包括两阶括语义分割(为每个像素分配类别标签)和实例分Inception等是当前最主流的分类算法,它们通过段方法(如R-CNN系列)和单阶段方法(如割(区分同类别的不同物体实例)U-Net、多层卷积和池化操作自动提取图像特征,实现端到YOLO、SSD)这些算法能够同时检测多个物Mask R-CNN等算法在医学影像分析、自动驾驶端的分类这些算法在医疗诊断、自动驾驶、安防体,在商品识别、人脸检测、安全监控等场景中应场景理解和视频编辑等领域发挥重要作用监控等领域有广泛应用用广泛计算机视觉算法使机器能够看见和理解视觉世界,是人工智能的重要分支除了上述核心任务外,计算机视觉还包括特征提取(SIFT、HOG等)、光流计算、3D重建、姿态估计等多种算法这些算法共同构成了现代视觉系统的基础大数据与算法处理与分析方法数据洞察从处理后的数据中提取价值和决策支持1数据分析2应用统计和机器学习算法挖掘数据模式数据处理使用分布式计算框架转换和聚合数据数据收集通过各种渠道获取并存储原始数据大数据处理面临5V挑战数据量大(Volume)、种类多(Variety)、生成快(Velocity)、真实性验证难(Veracity)和价值密度低(Value)为应对这些挑战,分布式计算框架如Hadoop(基于MapReduce范式)和Spark(内存计算框架)应运而生,它们将计算任务分散到多台机器上并行执行,显著提高处理效率在大数据分析中,常用算法包括分布式机器学习算法(如分布式梯度下降)、流处理算法(处理实时数据流)、近似算法(在可接受误差范围内提供快速结果)、采样算法(基于数据子集进行推断)等大数据技术与算法已在多个行业带来变革,如个性化推荐、智能交通、精准医疗、金融风控等随着数据量持续增长和分析需求不断提高,更高效的大数据算法仍在不断涌现机器人与算法引入机器人领域的算法应用路径规划算法使机器人能够在环境中找到从起点到目标的最优路径,避开障碍物常用算法包括A*搜索、RRT(快速随机树)、势场法等这些算法在自主移动机器人、无人驾驶车辆和工业机械臂中广泛应用定位与地图构建帮助机器人确定自身位置并建立环境地图的SLAM(同时定位与地图构建)算法粒子滤波、卡尔曼滤波和图优化方法是解决SLAM问题的主要方法,对自主导航至关重要机器视觉算法使机器人能够看见并理解周围环境包括物体检测与识别、姿态估计、深度感知等算法,这些技术使机器人能够识别物体、判断距离并进行精确操作控制算法负责机器人的动作执行与稳定性从经典PID控制到现代强化学习方法,这些算法实现了从简单动作到复杂技能的控制,确保机器人动作精确且平稳机器人技术是算法应用的重要前沿领域,它将计算能力转化为物理世界的行动能力现代机器人系统是多种算法协同工作的复杂集合感知算法处理传感器数据,认知算法进行决策规划,控制算法执行具体动作,这些算法共同赋予机器人自主性和适应性随着深度学习的兴起,机器人算法也在迅速发展端到端学习方法让机器人能够直接从原始感知数据学习复杂行为;模仿学习使机器人通过观察人类示范来学习技能;强化学习使机器人通过不断尝试和改进掌握新任务这些进步正推动机器人从高度结构化的工业环境走向更加复杂多变的开放世界,开拓更广阔的应用前景算法案例如何解决实际问题物流配送路线优化金融欺诈检测医疗资源调度物流公司面临每天上千个包裹的配送挑战,需要在满银行需要从每天数百万笔交易中识别出可疑的欺诈行大型医院需要协调医生、病房、手术室等多种资源,足时间窗口约束的同时最小化行驶距离这本质上是为该问题的特点是数据极度不平衡(欺诈案例很为患者提供高效医疗服务这是一个复杂的多资源约一个带约束的车辆路线规划问题(CVRP)算法方少)且模式快速变化算法方案采用了多层防御策束调度问题算法方案使用了约束规划(CP)与启案结合了启发式算法(如模拟退火、遗传算法)和精略规则引擎过滤明显异常;无监督学习(如One-发式搜索相结合的方法,考虑了医生专长、设备可用确算法(如分支定界、动态规划),在可接受的计算Class SVM、Isolation Forest)检测异常模式;监性、患者优先级等多种因素系统实现后,患者等待时间内得到接近最优的配送方案,减少了25%的燃油督学习(如梯度提升树、神经网络)基于历史数据进时间平均减少35%,资源利用率提高20%,同时保证成本和30%的配送时间行精细分类该系统实时评估交易风险,将欺诈损失了紧急情况的快速响应降低了40%实际问题的算法解决往往不是简单应用教科书中的标准算法,而是需要深入理解问题本质,结合领域知识,设计适合特定场景的算法方案成功的算法解决方案通常具有以下特点问题建模准确、算法选择合理、实现高效稳定、能够适应变化面试技巧如何应对算法题目的考察优化与反思沟通与表达完成初步解法后,主动分析时间和空间解题四步法清晰表达思路比快速得出答案更重要复杂度,思考可能的优化方向讨论算面试前准备面对算法题时,遵循结构化的解题步在编码前先口头描述解决方案,使用图法在不同场景下的表现,以及如何处理系统复习核心数据结构和算法,包括数骤1)仔细理解问题,确认输入输出和表辅助说明,征求面试官反馈编写代大规模数据或高并发情况面试后反思组、链表、栈、队列、树、图以及排约束条件;2)设计解决方案,可从暴力码时注重可读性,适当添加注释遇到解题过程,总结经验教训,持续改进解序、搜索、动态规划等算法针对应聘解法开始逐步优化;3)编写清晰正确的困难不要急躁,可以请求提示或讨论思题策略和编码能力公司常见的题型进行有针对性练习,如代码;4)测试代码,考虑边界情况解路,展示学习能力和团队协作精神互联网公司偏好图算法和系统设计,金题过程中保持与面试官的交流,展示思融科技公司重视数据处理和优化等考过程算法面试不仅考察编码能力,更考察问题解决和沟通能力面试官关注的是解决问题的思路和过程,而非仅仅是得到正确答案保持冷静、系统思考、清晰表达是成功的关键即使遇到不熟悉的问题,也可以通过分析思路、提出多种可能的解法来展示你的问题分析能力扩展阅读与资源推荐书籍与在线资源深入学习算法与编程需要优质的学习资源经典书籍如《算法导论》(Introduction toAlgorithms)提供了系统全面的算法理论基础;《算法》(Algorithms)由Princeton大学Robert Sedgewick教授编写,配有Java实现;《数据结构与算法分析》侧重实际应用;《编程珠玑》(Programming Pearls)展示了优雅的问题解决思路在线平台如LeetCode、Codeforces提供了大量编程练习题;Coursera、edX上有来自顶尖大学的算法课程;GitHub上的开源项目可以学习实际应用中的算法实现此外,Stack Overflow、GeeksforGeeks等社区是解决编程问题的宝贵资源选择适合自己学习阶段的资源,结合理论学习与实践练习,才能建立扎实的算法基础与常见问题解答FAQ QA最后思考算法与编程的未来人工智能驱动的开发量子计算的影响生物启发算法AI辅助编程工具如GitHub量子计算的发展将彻底改变从自然界获取灵感的算法将Copilot正在改变开发流某些领域的算法设计量子持续发展,如神经网络(受程,未来程序员的角色可能算法如Shor算法、Grover大脑启发)、遗传算法(受从编写具体代码转向定义问算法在密码学、搜索等领域进化启发)、蚁群算法(受题、审核和优化AI生成的解展现出巨大潜力传统算法社会性昆虫启发)等这些决方案算法设计也将越来研究将与量子算法研究并行算法在复杂优化问题、自适越多地借助AI技术,形成人发展,针对不同硬件平台优应系统和分布式控制中展现机协作的开发模式化解决方案出独特优势算法伦理与公平性随着算法在社会决策中的作用增强,算法透明度、公平性和伦理问题变得日益重要未来的算法研究将更加注重减少偏见、增加可解释性和确保多样性,这也将成为算法设计的重要维度算法与编程的未来将由多种力量共同塑造计算硬件的演进(从多核到量子计算)、问题规模的扩大(大数据时代的挑战)、应用领域的拓展(从科学计算到社会系统)以及开发范式的变革(低代码、AI辅助开发)结束语新一代的算法与编程探索者探索精神保持好奇,敢于尝试新技术和方法创新思维突破传统思路,寻找问题的创新解法分享合作参与开源社区,与他人共同进步社会影响思考技术对社会的责任和贡献在这个信息技术飞速发展的时代,我们既是技术的使用者,也是技术的创造者作为新一代的算法与编程探索者,你们肩负着推动技术进步、解决复杂问题的使命算法与编程不仅是职业技能,更是解决问题的方法论和思维方式,它们将帮助你在任何领域取得成功希望本课程为你打开了计算机科学的大门,点燃了你对算法与编程的热情学习是永无止境的旅程,真正的大师永远保持学习的心态无论你未来选择什么样的道路,希望你能将这里学到的思维方式和问题解决能力融入生活和工作,创造属于自己的精彩篇章愿你在数字世界的探索之旅中不断成长,创造无限可能!。
个人认证
优秀文档
获得点赞 0