Data_structure&Algorithms&日常算法练习docs
算法学习方法
1.设定小目标
当你面对一个复杂的问题时,可能会感到压力或不知从何下手。为了避免这种情况,可以采用分步解决的策略:
(1)理解题目:先确保你清楚题目的要求,理解输入输出和需要解决的核心问题。
(2)理清思路:你可以先不着急写代码,而是拿出纸笔,画出问题的流程图或写出伪代码(用普通语言描述解决步骤)。
(3)逐步实现代码:先写出能完成部分功能的代码,再逐渐完善它。比如在做动态规划题目时,你可以先尝试暴力解法,然后逐步优化。
(4)逐步挑战自己: 从简单的题目开始,让自己有成就感。比如,先完成数组和字符串的简单操作,再挑战递归或动态规划这类较难的题目。
2.延迟看答案【我不管,我要一点不会就问AI,嘿嘿嘿,我是笨蛋】
很多人在遇到困难时,容易直接去看答案。
这虽然能迅速解决问题,但会削弱你自主思考的能力。
为了避免这种情况,你可以设定一定的时间限制,强迫自己在限定时间内独立思考。
自我提问: 在解题过程中,尝试通过自我提问来引导自己解决问题。
这可以帮助你形成更系统的解题思路。
常见的提问包括:
输入和输出是什么?
——明确问题的目标。
我可以用哪些数据结构来处理这个问题?
——根据题目的特性选择合适的工具,比如数组、哈希表、栈等。
有没有相似的题目我做过?
——参考自己以前做过的类似题目,借用其中的解法。
尝试部分解法: 你不需要一次性解决所有问题。
即使只解决了问题的一部分,也值得记录下你的思路和部分代码。
然后对比答案,了解自己哪里出错或没有想到。
3.Python作为学习工具
Python 语言由于其简洁性和广泛的支持库,成为许多初学者学习算法的首选工具。
(1)基础练习: 在熟悉 Python 之前,确保掌握它的基本语法和数据结构。例如:
(2)数据类型:如 list(列表)、dict(字典)、set(集合)等。
(3)控制流:如 if 语句、for 和 while 循环等。
(4)函数和递归:学习如何编写函数,以及递归是处理复杂问题的一种重要方法。
LeetCode 的 Python 标签题目: LeetCode 上有很多人用 Python 解决问题,并在 Discuss 区分享高效解法。
你可以做题时参考这些高票答案,学习 Python 特有的简化写法,例如:
使用 collections.Counter 快速统计元素频率。
利用 Python 内置函数 sorted() 进行高效排序。
使用列表推导式、生成器等高效编写循环。
4.逐步进阶
为了让你的学习有层次感,可以从简单的题目入手,然后逐步挑战更复杂的题目。
以下是几个推荐的题型:
数组和字符串: Python 的内置数据结构非常适合处理这些题目。
你可以尝试使用列表操作(如切片、合并等)和字符串操作(如 split()、join()、replace() 等)解决问题。
哈希表: Python 的 dict(字典)和 set(集合)非常适合处理哈希表类问题。
比如在寻找重复元素、统计频率、快速查找等问题中,使用字典或集合可以极大提高效率。
双指针: 双指针技术用于处理排序数组或字符串的题目。
它的典型应用是在排序数组中寻找两个数的和。
移动窗口技术:用于解决子数组和的问题。
使用两个指针,一个从前一个从后同时进行遍历,可以节省时间。
5.记录和复盘
在解题过程中,记录和复盘是非常重要的学习步骤。它有助于加深理解并避免重复犯错。
写博客: 在 CSDN、GitHub 或 LeetCode 上写下你做题的过程,不仅可以帮助整理思路,还能记录你在哪些方面进步和遇到困难。
记录思路、错误原因以及改进方法可以让你在日后遇到类似问题时轻松应对。
复习错题: 定期回顾你之前做错或解决不顺利的题目,重点分析自己哪部分理解不足,为什么当时没能解决问题。
这样可以帮助你巩固之前的知识点,并提升后续做题的效率。
6.Python 学习资源
以下是一些有助于提升 Python 算法能力的资源:
LeetCode Discuss 板块: 在 LeetCode 的讨论区,可以看到很多高票的 Python 解答和讨论。
你可以学习到很多简洁且高效的 Python 写法。
定期浏览这些讨论,了解其他人的思路,并反思如何改进自己的代码。
Python 官方文档: 学习 Python 时,官方文档是一个重要的参考资源,特别是在你需要了解内置函数和库时。
比如 collections 模块包含很多非常实用的数据结构,如 Counter、deque 等,这些都能帮助你快速实现算法。
考研机试
算法参考资料
Hello-algo
oi wiki
算法cs61b
一本不错的题解 leetcode 101
LeetCodeAnimation
https://github.com/MisterBooo/LeetCodeAnimation
高校学生自发文档
CSwiki
清华计算机系科协技能文档
酒井科协暑培2024
酒井科协暑培2023
好用的标签页iTab
浙大本科生指南
复旦本科生指南
《算法设计与分析基础》
重要的问题类型
- 排序:就是把一堆乱序的数据按照特定的顺序(比如从小到大、从大到小)排列好。例如,将数字[5, 3, 1, 4, 2]排成[1, 2, 3, 4, 5]。
- 查找:在一堆数据里找到你想要的那个数据。就像在图书馆的很多书里找到你想看的那一本。
- 字符串处理:对由字符组成的字符串进行操作,比如判断一个字符串是不是另一个字符串的子串,或者把几个字符串拼接在一起等。
基本数据结构
- 树:想象一棵树,有根、有分支、有叶子。在数据结构里,树有节点,节点之间有父子关系,它可以用来表示层次结构的数据。比如公司的组织架构,董事长在最上面,下面是各个部门经理等。
- 图:由一些点(顶点)和连接这些点的线(边)组成。可以用来表示很多实际的网络关系,比如城市之间的道路连接情况。
- 列表:就是把数据一个一个按顺序排好,像购物清单一样。
- 集合:它里面的元素没有特定的顺序,而且每个元素都是唯一的,就像把不同的水果放在一个篮子里,每种水果只放一个。
算法效率分析(可以先跳过不看):这个部分是研究算法运行的快慢和占用内存空间的多少。
蛮力法:简单来说,就是不考虑技巧,用最直接、最笨的方法去解决问题。比如要在一个房间里找钥匙,蛮力法就是把房间里所有的东西都翻一遍。
减治法:把一个大问题逐步分解成规模较小的子问题,然后解决这些子问题,最后再把这些子问题的结果组合起来得到大问题的答案。就好像要吃一个大蛋糕,先把它切成小块,吃完小块再知道整个蛋糕的味道。
分治法:把一个大问题分成几个差不多大小的子问题,分别解决这些子问题,最后把它们的结果合并起来。和减治法有点像,但分治法的子问题通常规模比较均匀。
变治法:通过改变问题的表现形式或者性质来使问题更容易解决。
时空权衡:有时候为了让算法运行得更快(节省时间),可能需要占用更多的内存空间;或者为了节省内存空间,算法运行的速度就会慢一些。这就是在时间和空间之间进行权衡。
动态规划
-
动态规划:是一种解决多阶段最优化问题的方法。它把一个复杂的问题分解成多个简单的子问题,并且把这些子问题的结果保存起来,这样在遇到相同的子问题时就不用再重新计算了。
-
背包问题和记忆功能
- 背包问题:想象你有一个背包,它能装一定重量的东西,现在有很多不同重量和价值的物品,你要选择一些物品放进背包,使得背包里物品的总价值最大。
- 记忆化:在解决背包问题的时候,把已经计算过的子问题的结果保存起来,下次再遇到同样的子问题就直接使用这个结果,不用再计算一遍,这就是记忆化。
-
最优二叉查找树:二叉查找树是一种特殊的树结构,在这种树里查找数据很方便。最优二叉查找树就是在所有可能的二叉查找树中,让查找操作的平均成本最小的那棵树。
-
Floyd 算法:主要用于解决图中任意两点之间的最短路径问题。它通过不断更新两点之间的距离来找到最短路径。
-
Warshall 算法:用于求图的传递闭包,简单说就是确定图中任意两个顶点之间是否存在路径。
贪婪算法
- Prim 算法:用于在图中找到一棵最小生成树。它从一个顶点开始,每次都选择一条与当前生成树相连的最小权重的边,把新的顶点加入到生成树中。
- Kruskal 算法:也是求图的最小生成树的算法。它把图中的边按照权重从小到大排序,然后依次选择边,如果这条边加入后不会形成环,就把它加入到最小生成树中。
- Dijkstra 算法:用于在图中计算一个顶点到其他所有顶点的最短路径。它从一个起始顶点开始,每次找到距离起始顶点最近的一个顶点,然后更新这个顶点的邻居顶点到起始顶点的距离。
算法分类(第 4 - 10 章)
- 蛮力法:直接按最基本的方法尝试所有可能性。
- 减治法:逐步减小问题规模求解。
- 分治法:均匀划分问题为子问题求解。
- 变治法:改变问题形式求解。
- 时空权衡:平衡算法运行时间和占用空间。
- 动态规划:利用子问题结果优化求解过程。
- 贪婪:在每一步都选择局部最优的策略。
- 算法的极限:研究算法在解决某些问题上的能力边界。
- 超越算法的极限:可能是探讨一些突破传统算法限制的方法或者思路。
- 霍夫曼树:是一种特殊的二叉树,用于数据压缩等领域。它根据字符出现的频率来构建树,频率高的字符离根节点近,这样可以更有效地进行编码和解码。
《数据结构解题策略》
复旦大学吴永辉