前缀树:
举例: 如图所示 路径上标的是字符串中单个字符
升级 1(查找是否有特定字符串):
如果要查找"de"前缀的字符串,很好做到 但是查找是否有"de"字符串就不太好确定 (因为和"def"类似的结构是相同的)
所以 在刚才的基础上 在每个节点加上计数器 如果以此节点为末尾节点 则+1
升级 2 ( 确定含有特定前缀的字符串个数 ):
就在每个节点处开辟另一个参数区域 用来记录有几个字符串经过 经过一次 则区域计数+1
代码:
删除时候需要注意:如果某个节点已经为0 则其子节点也就不要了~~直接赋值为null
贪心策略
给定几个字符串,将它们拼接起来构成最小的字符串(字典序):
贪心策略1 : 按照分部字典序去拼接----不一定整体是字典序最前的。
贪心策略2: 如果拼接起来是字典序最前的 -----则按照这个排下来。
分析贪心策略:必须具有传递性----这样上述条件才成立
如果是在数字类型题中 ,可以根据字符串最终还原成连接起来的数字形式。
K进制 则 前面的a*k(b长度)+b----表示成整体连接之后的数字形式
证明可以得出:
再证明:
假设有a----b---- 证明a放在前面一定是最好的选择
贪心--分金条使代价最低:
思路: 类似于 霍夫曼树 最终统计的是 非叶子节点的总和
解决工具: 采用小根堆 每次取出其中最小的两个 类似于组建哈夫曼树 不断向上
直到堆中只剩下一个元素 最终统计所有的求和
主要核心: 在于我们想去寻找两个尽可能大小相当的 所以堆这个结构刚刚好
代码:
总结:
当总共的代价由子代价 累加或者累乘 时 ,可能还会有对应的公式 ,则可能用哈夫曼编码的思路做出来。
贪心--做有限项目使利润最大化:
题意: 有一批项目 每个项目对应两个参数 一个cost(成本) 一个profit(利润)
最初给定一笔启动资金W 每次只能执行一个项目 (必须在资金以内的项目)
最多做K个项目 如何使最终获得的钱数最大~
思路: 小根堆---按照花费排(小根堆存放全部的项目)---取出未超过启动资金的花费项目
----再进入大根堆---按照利润排----(大根堆存放解锁的项目)
不断的进行上述挑选--每次解锁一堆项目--从中拿出利润最大的进行---之后重复
代码:
贪心--在有限时间内使会议室内宣讲场次最多:
思路:
考虑几种可能的贪心策略: 1 开始时间早(然而结束时间超级晚)
2 持续时间短(然而 影响前后两个宣讲场次)
3 结束时间短的~~(为最可能的)
代码:
递归和动态规划:
求阶乘n! :
递归和非递归写法:
汉诺塔问题:
时间复杂度为 2(n)-1 n次方
打印一个字符串的全部子序列,包括空字符串。
递归法:
原理:类似于二叉树 到叶子节点就开始打印
打印字符串的全排列:
母牛数量:
列举出前几项:
规律总结:
二维数组的最小路径和:
思路:
从(i,j)点出发到右下角点的最小路径和:
1 如果(i,j)就是 右下角点 则路径和 返回该点值
2 如果已经到最后一行 则只能继续往右走 则该点值+右边点距离终点的最小路径和
3 如果已经到最后一列 则只能继续往下走 则该点值+ 下边点距离终点的最小路径和
4 如果是正常情况 可以向右 / 向下 则考察右端和下端具体最小路径和+ 该点值=最终最小路径和
此种方法复杂度较高:
由图中可以看出 重复状态出现次数太多---暴力递归
暴力递归改动态规划:
其实变成了从下往上 递归
1 写出尝试版本(递归形式)
2 分析可变参数 分析哪几个参数可以代表返回值状态 可变参数几维 ---几维表
3 观察需要的终止状态--在表中点出--回到base cases把完全不依赖的值设置好(如最后一行最后一列)
4 观察一个普遍位置 需要哪些位置 逆着回去 就是填表的顺序
给定数组和特定数字,是否能够累加求和为该数字?
思路:
先想递归:
代码:
两种选择中有一个为true即整体为true
从暴力递归转成动态规划:
特殊情况考虑: 数组中全部数字总和都<aim 直接返回false即可
考虑是否具有后效性 (与前面的选择无关)
考虑可变参数 数组固定数字固定 只有i和sum不固定
画出dp图:最后一行是定的 由base case确定的