词梯Word Ladder问题

  • 要求是相邻两个单词之间差异只能是1个字母,如FOOL变SAGE:
FOOL >> POOL >> POLL >> POLE >> PALE>> SALE >> SAGE
  • 目标是找到最短的单词变换序列

    • 用图表示单词之间的关系;
    • 用一种名为广度优先搜索 BFS的图算法找到从起始单词到结束单词的最短路径。

构建词梯图

算法

  • 首先是将所有单词作为顶点加入图中,再设法建立顶点之间的边
  • 对每个顶点(单词) , 与其它所有单词进行比较, 如果相差仅1个字母, 则建立一条边
  • 时间复杂度是O(n²),对于所有4个字母的5110个单词,需要超过2600万次比较

优化算法

  • 改进的算法是创建大量的桶, 每个桶可以存放若干单词

    • 桶标记是去掉1个字母,通配符“_”占空的单词
  • 所有匹配标记的单词都放到这个桶里
    • 所有单词就位后,再在同一个桶的单词之间建立边即可
  • 单词关系图是一个非常稀疏的图

采用字典建立桶

def buildGraph(wordFile):
d = {}
g = Graph()
wfile = open(wordFile, 'r')
for line in wfile:
word = line[:-1]
for i in range(len(word)):
bucket = word[:i]+'_'+[i+1:]
if bucket in d:
d[bucket].append(word)
else:
d[bucket] = [word] for bucket in d.keys():
for word1 in d[bucket]:
for word2 in d[bucket]:
if word1 != word2:
g.addEdge(word1, word2) return g

广度优先搜索 BFS (breadth first search)

在单词关系图建立完成以后, 需要继续在图中寻找词梯问题的最短序列

算法思路

  • 给定图G, 以及开始搜索的起始顶点s

    • BFS搜索所有从s可到达顶点的边
    • 而且在达到更远的距离k+1的顶点之前, BFS会找到全部距离为k的顶点
    • 可以想象为以s为根,构建一棵树的过程,从顶部向下逐步增加层次
    • 广度优先搜索能保证在增加层次之前,添加了所有兄弟节点到树中
  • 为了跟踪顶点的加入过程, 并避免重复顶点, 要为顶点增加3个属性
    • 距离distance:从起始顶点到此顶点路径长度;
    • 前驱顶点predecessor:可反向追溯到起点;
    • 颜色color:
      • 标识了此顶点是尚未发现(白色)
      • 已经发现(灰色)
      • 还是已经完成探索(黑色)
  • 还需要用一个队列Queue来对已发现的顶点进行排列

    决定下一个要探索的顶点(队首顶点)

算法过程

从起始顶点s开始, 作为刚发现的顶点,标注为灰色, 距离为0, 前驱为None,加入队列, 接下来是个循环迭代过程:

  • 从队首取出一个顶点作为当前顶点;
  • 遍历当前顶点的邻接顶点,如果是尚未发现的白色顶点,则将其颜色改为灰色(已发现),距离增加1,前驱顶点为当前顶点,加入到队列中
  • 遍历完成后,将当前顶点设置为黑色(已探索过),循环回到步骤1的队首取当前顶点





代码

  • 在以FOOL为起始顶点, 遍历了所有顶点, 并为每个顶点着色、 赋距离和前驱的代码
def bfs(g, start):
start.setDistance(0)
start.setPred(None)
vertQueue = Queue()
vertQueue.enqueue(start)
while(vertQueue.size > 0):
currentVert = vertQueue.dequeue()
for nbr in currentVert.getConnections():
if(nbr.getColor() == 'white'):
nbr.setColor('gray')
nbr.setDistance(currentVert.getDistance()+1)
nbr.setPred(currentVert)
vertQueue.enqueue(nbr)
currentVert.setColor('black')
  • 最后,通过一个回途追溯函数来确定FOOL到任何单词顶点的最短词梯!
def traverse(y):
x = y
while(x.getPred()):
print(x.getId())
x = x.getPred()
print(x.getId())

完整代码

def buildGraph(wordFile):
d = {}
g = Graph()
wfile = open(wordFile, 'r')
for line in wfile:
word = line[:-1]
for i in range(len(word)):
bucket = word[:i]+'_'+[i+1:]
if bucket in d:
d[bucket].append(word)
else:
d[bucket] = [word] for bucket in d.keys():
for word1 in d[bucket]:
for word2 in d[bucket]:
if word1 != word2:
g.addEdge(word1, word2) return g def bfs(g, start):
start.setDistance(0)
start.setPred(None)
vertQueue = Queue()
vertQueue.enqueue(start)
while(vertQueue.size > 0):
currentVert = vertQueue.dequeue()
for nbr in currentVert.getConnections():
if(nbr.getColor() == 'white'):
nbr.setColor('gray')
nbr.setDistance(currentVert.getDistance()+1)
nbr.setPred(currentVert)
vertQueue.enqueue(nbr)
currentVert.setColor('black') def traverse(y):
x = y
while(x.getPred()):
print(x.getId())
x = x.getPred()
print(x.getId()) if __name__ == "__main__":
wordgrah = buildGraph("fourletterwords.txt")
bfs(wordgrah, wordgrah.getVertex('FOOL'))
traverse(wordgrah.getVertex('SAGE'))

算法分析

  • BFS算法主体是两个循环的嵌套

    • while循环对每个顶点访问一次,所以是O(|V|)
    • 而嵌套在while中的for,由于每条边只有在其起始顶点u出队的时候才会被检查一次
    • 而每个顶点最多出队1次,所以边最多被检查1次,一共是O(|E|)
    • 综合起来BFS的时间复杂度为O(|V|+|E|)
  • 词梯问题还包括两个部分算法
    • 建立BFS树之后, 回溯顶点到起始顶点的过程,最多为O(|V|)
    • 创建单词关系图也需要时间,最多为O(|V|2)

【数据结构与算法Python版学习笔记】图——词梯问题 广度优先搜索 BFS的更多相关文章

  1. 【数据结构与算法Python版学习笔记】目录索引

    引言 算法分析 基本数据结构 概览 栈 stack 队列 Queue 双端队列 Deque 列表 List,链表实现 递归(Recursion) 定义及应用:分形树.谢尔宾斯基三角.汉诺塔.迷宫 优化 ...

  2. 【数据结构与算法Python版学习笔记】引言

    学习来源 北京大学-数据结构与算法Python版 目标 了解计算机科学.程序设计和问题解决的基本概念 计算机科学是对问题本身.问题的解决.以及问题求解过程中得出的解决方案的研究.面对一 个特定问题,计 ...

  3. 【数据结构与算法Python版学习笔记】图——最短路径问题、最小生成树

    最短路径问题 概念 可以通过"traceroute"命令来跟踪信息传送的路径: traceroute www.lib.pku.edu.cn 可以将互联网路由器体系表示为一个带权边的 ...

  4. 【数据结构与算法Python版学习笔记】图——强连通分支

    互联网 我们关注一下互联网相关的非常巨大图: 由主机通过网线(或无线)连接而形成的图: 以及由网页通过超链接连接而形成的图. 网页形成的图 以网页(URI作为id)为顶点,网页内包含的超链接作为边,可 ...

  5. 【数据结构与算法Python版学习笔记】图——骑士周游问题 深度优先搜索

    骑士周游问题 概念 在一个国际象棋棋盘上, 一个棋子"马"(骑士) , 按照"马走日"的规则, 从一个格子出发, 要走遍所有棋盘格恰好一次.把一个这样的走棋序列 ...

  6. 【数据结构与算法Python版学习笔记】图——拓扑排序 Topological Sort

    概念 很多问题都可转化为图, 利用图算法解决 例如早餐吃薄煎饼的过程 制作松饼的难点在于知道先做哪一步.从图7-18可知,可以首先加热平底锅或者混合原材料.我们借助拓扑排序这种图算法来确定制作松饼的步 ...

  7. 【数据结构与算法Python版学习笔记】图——基本概念及相关术语

    概念 图Graph是比树更为一般的结构, 也是由节点和边构成 实际上树是一种具有特殊性质的图 图可以用来表示现实世界中很多有意思的事物,包括道路系统.城市之间的航班.互联网的连接,甚至是计算机专业的一 ...

  8. 【数据结构与算法Python版学习笔记】查找与排序——散列、散列函数、区块链

    散列 Hasing 前言 如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度. 现在我们进一步来构造一个新的数据结构, 能使得查找算法的复杂度降到O(1), 这种概念称为" ...

  9. 【数据结构与算法Python版学习笔记】算法分析

    什么是算法分析 算法是问题解决的通用的分步的指令的聚合 算法分析主要就是从计算资源的消耗的角度来评判和比较算法. 计算资源指标 存储空间或内存 执行时间 影响算法运行时间的其他因素 分为最好.最差和平 ...

随机推荐

  1. kubeadm方式搭建K8S集群

    一.kubeadm介绍 二.安装要求 三.集群规划 四.环境初始化(在每个服务器节点操作) 1.关闭防火墙 2.关闭selinux 3.关闭swap 4.根据规划设置主机名 5.在Master添加ho ...

  2. matlab纹理映射之地球

    %地球 cla reset; load topo; [x,y,z] = sphere(45); s = surface(x,y,z,'facecolor','texturemap','cdata',t ...

  3. 第09课:GDB 实用调试技巧(下)

    本节课的核心内容: 多线程下禁止线程切换 条件断点 使用 GDB 调试多进程程序 多线程下禁止线程切换 假设现在有 5 个线程,除了主线程,工作线程都是下面这样的一个函数: void thread_p ...

  4. word文档转成图片

    1:先把word文档转成pdf格式  这个是在word中转成pdf格式,保存好 2:再把pdf格式转成图片 在这个链接中打开https://smallpdf.com/cn/pdf-converter, ...

  5. 地址栏url中去掉所有参数

    1.地址栏url中去掉所有参数,这个是纯前端解决,很多时候页面跳转时候会选择在url后面带参数过去,(使用?&),方便传也方便取,但是我们要做的是不要让页面的一些请求参数暴露在外面 正常项目工 ...

  6. python多继承简单方法

    class people(object): #建创一个人类 def __init__(self,name,age): self.name = name self.age = age def eat(s ...

  7. 【Sass/SCSS 完整自学中文版教程01】SCSS 官方英文文档翻译整理

    Sass 基本介绍 目录 Sass 基本介绍 注释(Comments) 单行注释(Single-line comments) 多行注释(Multi-line comments) SassDoc 特殊的 ...

  8. CentOS安装oh-my-zsh并配置语法高亮和命令自动补全

    安装zsh 和 oh-my-zsh 安装zsh yum install zsh 安装git yum install git 切换默认shell chsh -s /bin/zsh clone from ...

  9. 论文解读(DGI)《DEEP GRAPH INFOMAX》

    论文标题:DEEP GRAPH INFOMAX 论文方向:图像领域 论文来源:2019 ICLR 论文链接:https://arxiv.org/abs/1809.10341 论文代码:https:// ...

  10. DS博客作业04--图

    这个作业属于哪个班级 数据结构--网络2011/2012 这个作业的地址 DS博客作业04--图 这个作业的目标 学习图结构设计及相关算法 姓名 黄静 目录 0.PTA得分截图 1.本周学习总结 1. ...