当前位置: 首页 > news >正文

B站左神算法课学习笔记(P8):贪心

一、前缀树

1、什么是前缀树?

2、前缀树的代码实现

(1)创建节点

(2)插入节点

(3)查询某个单词

(4)查询前缀

(5)删除某个单词

二、贪心算法

1、经典例题——安排会议:

2、严格证明贪心策略的艰难

3、例题:分金条(哈夫曼编码)

4、例题:项目利润

三、堆题目补充

1、数据流与中位数

四、N皇后问题

1、基础解法

2、优化


一、前缀树

1、什么是前缀树?

如下图,经典前缀树:信息储存在边上;对每个字符串中的字符,若有从原点出发相同的路径(字符),则复用;若没有,则新建。

2、前缀树的代码实现

(1)创建节点

节点一般需要携带更多信息,如下面代码所示:

另一个例子:

当如下前缀树存储 ["abc", "ab", "bc", "bck"] 这条信息,可以实现:

        (1)查询特定字符串是否出现(查是否出现过"bc":依次查b-c,看c节点处e的值);

        (2)查有多少个以"ab"开头的字符串(依次查a-b看b节点处e的值)【哈希表做不到】;

tips:该查询代价极小,代价仅是字符串的长度!

(2)插入节点

代码实现:

而对于空串(""),root节点pass++,end++!

实际上,若字符种类太多,考虑到浪费空间,可以考虑使用哈希表的方式来存储路径信息:

HashMap<Char, Node> nexts;

进一步地,若希望路与路之间有序组织,而非像哈希表一样散列,可以使用有序表:

TreeMap<Char, Node> nexts;

(3)查询某个单词

思路:若输出词不为空,则拆为数组依次查看路径;若没有指定的某一条路径,则返回0;若成功遍历到指定路径的地步,则返回node.end

(4)查询前缀

思路:(基本同上)若输出词不为空,则拆为数组依次查看路径;若没有指定的某一条路径,则返回0;若成功遍历到指定路径的地步,则返回node.pass

(5)删除某个单词

思路:现搜索是否有该词,若有:沿途node.pass--;终点node.end--。

例:在下方前缀树中,删除一个"abc":

特殊情况:当删除一个单词后,部分节点的p值变为0,则需要把其后方的路径全部删除!

代码实现:

tips:中间删除时,java只需要将索引置空即可,jvm会自动释放内存;而c++则需手动遍历到每一个节点后依次释放!

二、贪心算法

定义:在某一标准下,优先考虑最满足标准的样本,最后考虑最不满足标准的样本,最终得到的一个答案的算法,叫做贪心算法。(即求局部最优解

但是注意证明:局部最优解需推到整体最优解

1、经典例题——安排会议:

结合下图理解: 

按照上图右侧的代码实现:(贪心的代码实现都很短,熟悉了很好做!!)

重点:别去纠结!贪心本质上是有技巧地

2、严格证明贪心策略的艰难

该部分以一个例题为例,详细说明严格证明贪心策略有多么艰难,以劝告各位,不要尝试证明!

Q:给定一组字符串,要求它们拼接起来后的字典序最小。

旧的贪心策略可以轻松举出反例:对于字符串组 ["b", "ba"],若按照旧贪心策略,则是"bba";但是其实最小的字典序应该是"bab",故旧贪心策略错误。

下面严格证明为什么新贪心策略正确:

(1)首先证明比较策略是有效的 -——> 看是否有传递性

有效,即,对于不同的原始数据,我们总能得到同样的排序结果;

下图是一个反例,因为形成了环,导致对于不同的原始数据可能得到不同的比较结果,所以是无效的比较策略:

无效的比较策略

开始证明传递性:

前提假设
传递性的证明

到此为止,已知我们的排序策略有效,可以排出一组唯一的序列出来。

(2)证明已排序的序列,交换任意两个元素后,字典序会变大

Case1:a、b相邻,可借助上述 a.b<=b.a 的结论:

Case2:a、b不相邻时,根据根据Case1的结论递推可知:

(3)使用数学归纳法继续证明交换3个数、交换4个数等等都会产生更大的字典序。

进而证明贪心策略有效!

所以:应该采用对数器,使用实验方式来验证!!!

3、例题:分金条(哈夫曼编码)

思路:采用小根堆实现:

代码实现:

4、例题:项目利润

题目理解:假设有如下5个项目,初始资金为1,所以只能按照下面的顺序做三个项目。虽然总共允许做四个项目,但是后面项目的资金要求无法满足,故做3个项目后停止。

解题思路:

建立两个堆:1、锁定的项目:根据项目所需花费建立小根堆,按照当前资金解锁项目;

2、解锁的项目:根据项目利润,将从上述堆中弹出的项目建立大根堆;

代码实现:

定义存储结构
定义比较器
核心逻辑代码

贪心策略小结:根据你确立的标准,依次考察每个样本。

三、堆题目补充

1、数据流与中位数

Q:若用户给你输入一个数据流,你需要维持一个数据结构,使得你可以随时取出所有数据流中的中位数。

为什么快:每次输入时,大根堆和小根堆的调整都是O(logN)水平!

四、N皇后问题

1、基础解法

代码实现:

深度优先遍历(DFS)

上面代码可以结合下图(八皇后)理解:

下面时 isValild() 方法的具体实现:

2、优化

采用位运算,优化 record 中挨个查询!!

32位是由于 int 限制,若需要可改为 long
其中 colLim == limit 是base case,即所有列都不能填,即为找到了一种能拜访所有皇后的位置

可结合下图理解:

对所有为限制取 || (或)操作

相关文章:

  • Python函数一(五)
  • 算法 | 基于蜘蛛蜂优化算法求解带时间窗的车辆路径问题研究(附matlab代码)
  • ZKmall开源商城:基于Spring Boot 3的高效后端架构设计与实践
  • 三维点云数据的哈希快速查找方法
  • linux驱动学习(十五)之ioctl
  • 软件工程面试题(三十)
  • 【Android】界面布局-相对布局RelativeLayout-例子
  • 网络基础二
  • linux专题3-----禁止SSH的密码登录
  • 论文阅读笔记——RDT-1B: A DIFFUSION FOUNDATION MODEL FOR BIMANUAL MANIPULATION
  • R 语言科研绘图第 36 期 --- 饼状图-基础
  • 大厂不再招测试?软件测试左移开发合理吗?
  • C 语言排序算法:从基础到进阶的全面解析一、引言
  • Deep Reinforcement Learning for Robotics翻译解读
  • 【Python使用】嘿马云课堂web完整实战项目第3篇:增加数据,修改数据【附代码文档】
  • Python菜鸟教程(小程序)
  • UE5把动画导出为视频格式
  • CentOS 7上配置SQL Server链接其他SQL Server服务器
  • 【HTML】纯前端网页小游戏-戳破彩泡
  • 算法刷题记录——LeetCode篇(2.3) [第121~130题](持续更新)