内容简介:给定两个字串x和y,将x变成y所需要改变的字符的个数是多少?期间可以的操作是:字串可以是非连续的。它等效于找两个字符串的最大公共字串,比如 HIEROGLYPHOLOGY 和 MICHAELANGELO 最大公共字串为 HELLO数量为:
给定两个字串x和y,将x变成y所需要改变的字符的个数是多少?期间可以的操作是:
- 插入字符c 耗时O(1)
- 删除字符c 耗时O(1)
- 将c更新为c' 如果C和C'是相同的,耗时O(0),其它不考虑
字串可以是非连续的。它等效于找两个字符串的最大公共字串,比如 HIEROGLYPHOLOGY 和 MICHAELANGELO 最大公共字串为 HELLO
动态规划思路
- 子问题:X的子串X[i:]和Y的子串Y[j:]
数量为:
DP(i,j)=min(cost of replace X[i] to Y[j]+ DP(i+1,j+1),cost of delete X[i]+DP(i+1,j),cost of insert Y[j]+DP(i,j+1) )
子问题的耗时:O(1)
- 拓扑排序:三个方向由右下角向左下角开始执行
for i in 0,...,|x|: for j in 0,...,|y|: 复制代码
原始的问题:DP(0,0),总的时间为:O(1)*O(|x||y|)
矩阵相乘在哪个部分加括号运算才能使得运算最优
假设有如下形式的矩阵做乘法
如果直接按照顺序来计算,先乘A.B,得到的结果再乘C
如果优先运算 B.C ,结果再乘A
可以看到第二种方式消耗的时间会更少。
扩展到假设有n个矩阵相乘那么如何实现通过加括号的方式来最优执行效率呢?
思路
最终总会是两个矩阵相乘,那这两个矩阵是怎么计算得到的?假设有一次区分,那么它是( ).( )这种样子,左边括号中也会继续按照这种方式划分,同理右边也需要,当左右两边都需要类似计算的时候,这种时候通常就是取substring
动态规划解决思路
- 找到子问题:计算
子问题的个数为 。每次选择相当于1分为2
- 猜测:最后该执行那个部分的计算?
执行应该是( ).( )这种样子 有的选择的数量:O(n)。去尝试所有的可能
- 循环:
需要分别计算左边括号的部分和右边括号的部分,以及最后计算出来的左右两个部分的乘积
DP(i,i+1)=0
子问题的时间:O(n)。D(i,k)的计算忽略不计,只有k的选择存在循环
- 拓扑执行顺序:增加子问题的大小
总时间消耗:
- 原始的问题为:DP(0,n)
如何使得词在段落中的位置分配合理,使得更美观
给定一个词的集合words,使用badness(i,j)表示使用的单词是words[i,j]
目标就是使得分出来的词展示在各个行,使得 最小
不好看的展示如下
blah blah blah b l a h verylongworld 复制代码
希望它能展示成
blah blah blah blah verylongworld 复制代码
暴力解决方案
一个个的去尝试所有单词的划分,也就是说,去判断任意一个词,是否应该在它的位置换行,如果有n个单词的话,总共需要尝试的次数是
动态规划
按照标准的动态规划步骤来进行:
- 找到子问题:集合的后缀 words[i:]
假设找到了第一行的分隔点,那么接下来需要考虑的是第二行又该在哪儿开始换行呢?依次继续往下去查找,所以需要思考的子问题就是去掉第一行的词之后,剩下的那些单词
子问题的数量:n。只有n个单词,后缀的次数也就是这些
- 猜测:第二行从哪儿开始?
猜测的选择的数量:<=n-i=O(n)。每次选完了第一行,只需要在剩下的单词里面选
- 循环:
DP[i]=min(badness(i,j)+DP[j] for j in range(i+1,n+1))
定义问题为求DP(i)的最小值。当i=n的时候,是没有单词剩下的,花销是0。
假设第一次在第i个位置开始换行,第一行的计算发方式为 badness(i,j),剩下的需要解决的问题部分是从i+1开始的单词,也就是剩下部分的花销假设从j开始,它可能取得剩下部分的任意值,每个j的取值所需要的花销就是D(j),那么这两部分相加最小时,也就是最优的划分方式
循环部分耗时(每个子问题耗时):O(n)。j总共有n种选择,加法部分是常量
- 拓扑排序:i=n,n-1,...,0
需要先从最末端开始计算,再一层层的网上去累加 时间为:问题的数量*每个问题的花销=
- 检验原始问题是否解决:即DP(0)是否解决
使用一个指针parent来表明j中的最小值是那个,那么沿着parent指针,0->parent[0]->parent[parent[0]]一直到最后,即可得到最佳的划分方式
吉他放手指的问题
有一个吉他,在弹的时候,可以用任何一个手指来谈,那么如果给予一系列的音符notes,每个音符都需要用手(手指头取值 1,..,F)处理,每个手指去某个音符弹后需要移到另一个音符用一个手指去弹,假设描述这种移动使用d(p,f,q,g)表示花销,那如何去使得花销最小?
d(p,f,q,g):表示手指f移动到g,弹的音符从p到q
一般思考是:
- 子问题:notes[i:],即后面的音符怎么去弹
- 猜测:该用那个手指头来谈音符i
- 循环:可以选择任意一个手指头去弹新的音符,但是当从旧的音符切换到新的音符去弹的时候,无法知道该切换到那个手指: DP(i)=min(DP(i+1)+d(i,f,i+1,?) for f in 1,..F)
所以子问题"记住"的过少,需要增加考虑的情况。
正确思路为:
- 子问题:notes[i:],即后面的音符怎么去弹,同时该那个手指f去弹notes[i:]
- 猜测:使用手指g来谈notes[i+1]
- 循环: DP(i,f)=min(DP(i+1,g)+d(i,f,i+1,g) for g in 1,..F)
i表示note[i]的音符
- 拓扑排序
for i in reversed(range(n)): //所有的音符 for f in 1...F: //每个手指头都有可能来弹音符 复制代码
最终去解决原始问题,DP(0,f),但是需要指定f,所以使用 min(DP(0,f) for f in 1,...,F),即初始的时候应该选择那一个手指去谈第一个音符
这种场景即是要考虑更多的情况,来达到最优解
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Flink Checkpoint超时问题常见排查思路
- 【特征提取+分类模型】4种常见的NLP实践思路
- Flink on YARN(下):常见问题与排查思路
- 阿里巴巴大规模应用 Flink 的实战经验:常见问题诊断思路
- 高性能服务器架构思路,不仅是思路
- 常用算法设计思路
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
程序员的算法趣题
[ 日] 增井敏克 / 绝 云 / 人民邮电出版社 / 2017-7 / 55.00元
本书是一本解谜式的趣味算法书,从实际应用出发,通过趣味谜题的解谜过程,引导读者在愉悦中提升思维能力、掌握算法精髓。此外,本书作者在谜题解答上,通过算法的关键原理讲解,从思维细节入手,发掘启发性算法新解,并辅以Ruby、JavaScript等不同语言编写的源代码示例,使读者在算法思维与编程实践的分合之间,切实提高编程能力。 本书适合已经学习过排序、搜索等知名算法,并想要学习更多有趣算法以提升编程技巧......一起来看看 《程序员的算法趣题》 这本书的介绍吧!