学习算法 golang版本
主要通过 极客时间-数据结构与算法之美 和 慕课网的算法课学习的算法知识, 自己整理出golang版本的基础的算法和数据结构;
基本上每个方法都是单元测试;
里面也有些自己做的leetcode的题目和课程中题目,解答思路都在代码的注释中
其中还有游戏中常用功能的算法问题
量级: 随数量递增而递增a 公式会把常量和低次项都忽略就得到下面
- O(1) 常熟阶
- O(logn) 对数阶
- O(n) 线性阶
- O(nlogn) 对数线性阶
- O(n^2) 指数阶
- O(n!) 阶乘阶
如何实际验证一个算法的时间复杂度?
可以将测试的数据规模每次比前一次翻倍,然后记录算法消耗的时间,将测试规模与消耗时间画在一个坐标系中,
根据函数图像可以大致判断时间复杂度
数据量级的概念,1s内完成处理
O(n^2) 10^4
O(n) 10^8
O(nlogn) 10^7
- 最好情况时间复杂度(best case time complexity)
- 最坏情况时间复杂度(worst case time complexity)
- 平均情况时间复杂度(average case time complexity)
- 均摊时间复杂度(amortized time complexity) (golang的slice扩容就需要用到均摊,在扩容的那次的操作会比非扩容操作耗时)
- 数组
- lru缓存算法
- 链表
- 问题
- 判断单链表是否有环
- 反转链表
- 找到链表的中间节点
- 两个有序单链表合并
- 删除倒数第N个节点
- 答案在 链表结构文件中
- 问题
- 栈
- 队列
- 排序
- 二分查找 似于数学中的夹逼定理,两边不断逼近某个值
- 二分法求平方根
- 查找第一个值等于给定值的元素(有重复元素的切片)
- 查找最后一个值等于给定值的元素
- 查找第一个大于等于给定值的元素
- 查找第一个大于给定值的元素
- 查找最后一个小于等于给定值的元素
- 权重随机算法(游戏中很常用)
- 权重随机普通算法 只要随机的数量不多可以进行 O(n)级别
- 优化版: 使用计数排序,后通过二分查找,时间复杂度降到O(logn)级别
- 优化版2: 使用 Alias method 将时间复杂度降到 O(1)级别, 应用于权重项比较多的情况
- 游戏中排行榜实现
- 跳表sikplist 搜索是O(logn)级别的,查询很快的一个结构,用处很多,比如时间轮上挂着的链表可以替换成跳表
- 字符串相关
- 单串匹配
- 多串匹配
- 树
- 并查询集 主要用查询某个元素属于哪个集合,合并两个集合, 比如 可以判断迷宫中哪些点是否有连接
- 图相关
- a star 寻路算法
- dijkstra 寻路算法
- 拓扑排序 Kahn 算法可以判断依赖中是否有循环依赖出现
动态规划和递归回溯是我觉得在学习算法中感觉最难的部分,特别是动态规划 解题心路历程, 自顶向下思考(有重复子问题加上最优子结构,递归回溯+记忆化搜索),然后转成自底向上的思考(动态规划),列出递推公式求解
背包问题的分类
循环结构:
外循环nums,内循环target
循环结构:
外循环nums,内循环target
循环结构:
不考虑顺序 外循环nums,内循环target
考虑顺序 外循环target,内循环nums
循环结构:
考虑顺序 外循环target,内循环nums
循环结构:
最外层每个背包,内层其他背包的循环
- 最值
dp[i] = max/min(dp[i], dp[i-nums]+1)或dp[i] = max/min(dp[i], dp[i-num]+nums) - 是否存在
dp[i]=dp[i]||dp[i-num] - 排列组合
dp[i]+=dp[i-num]
所有的解题思路都在注释中
┌─────────────────┬─────────────────┬─────────────────┐
│ processed │ not needed │ unknown │
└─────────────────┴─────────────────┴─────────────────┘
0 i j n
──────────────────────────────────────────────────────►
[0,i) 已经处理的数据, [i,j) 还没处理的数据 [j,n)
┌──────────────────┬────────────────┬─────────────────┐
│ processed │ unknown │ processed │
└──────────────────┴────────────────┴─────────────────┘
0 i j n
─────────► ◄─────────
[0,i) [j,n) 已经处理
- 每次都要进区域的缩减 (避免死循环)
- 每次缩减都不能把答案排除 (查找模糊值使用,比如,第一个大于某个值)