判断resultset是否遍历到最后一条记录_装X的利器,图的BFS遍历,力扣第127题,单词接龙。...

60f3ccf91e89fa228d73b5b738c34666.png

最近的每日一题,出现了一道图的遍历,力扣第127题单词接龙。本篇文章整体都是讲解这道题的。首先要说明的是这篇题解的代码是我在评论区偷的(但是理解是自己写的)!!我们读书人的事,怎么能叫偷呢?算法这东西你学到了不就是自己的吗?

6a9e9938a5526d6b4d61dcd842d486f9.png

基础思路:仔细读过题之后,可以注意到题目中要求找到最短转换路径。此时可以确定使用BFS搜索,因为BFS可以计算出从根节点开始到达每个可到达节点的距离,我们只需要在这些距离中找到从begin出发到end的最短距离即可。

其中从begin到end的变化中每次改变只能变换一个字母,并且转换后的单词也在wordList中,因此我们可以根据这个两个条件从begin单词开始构建出一个图。(PS:图搜索算法可以用来发现图的结构,许多的图算法在一开始都会先通过搜索来获得图的结构,其他一些图算法则对基本的搜索进行优化。 ----算法导论是这么说的)

如何进行构建?首先BFS,肯定是使用队列的结构。我们可以从第一个单词开始,每次变换一个字母,如果该字母组成的新单词在wordList中,那么将该新单词入队,重复这一过程直到找到endWord

这一过程在图中的表现就是旧单词(hit)与新单词(hot)之间建立起了一条边。代码中循环遍历对应图中的表现即是从新的单词无限延伸,直到找到end。

需要注意的是,这两条边是可逆的,也就是说该结构是无序图。通俗一点放在代码里讲,其实就是说我们要有一个集合存放已经遍历过的元素,以防止两个单词互相转换或是遍历到了已经遍历过的词,增加不必要的开销,因为我们找的是最短路径。

开始操作:

1、准备工作

# 将列表变成一个哈希表,以便在O(1)时间内进行in操作,
# 判断单词是否在hash表内  (List中这个判断是O(n))。
word_set = set(wordList)
# BFS遍历需要使用队列的结构。同时以第一个单词(beginWord)为起点进行图的生成。
queue = deque()
queue.append(beginWord)
# 上面有提到过要使用一个集合来记录某个节点是否访问过。
visited = set(beginWord)
# 因为题目中有说明"所有的单词长度都相同",那么根据我们的刚才整理的思路,
# 也就是加粗部分,可以看到每个单词遍历的次数就是他的元素个数,比如hit,
# 它有三个字母就需要把h,i,t三个字母分别换成26个字母,看是否可以组成
# 新的单词在wordList中。因此,此处我们需要记录单词的长度,也就是后面
# 我们要用到的每个单词的遍历次数。
word_len = len(beginWord)
# 准备工作的最后肯定需要一个字段来计算我们走过的节点数量。
# 此字段从1开始,即要从自己本身出发。
count = 1
# 然后是两点特殊处理
# 1、当没有字典或者结束单词根本不在字典时候,直接返回0
# 2、把开始单词从字典中删除,因为我们已经使用开始单词作为队列的第一个元素了。
if len(word_set) == 0 and endWord not in word_set:
    return 0
if beginWord in word_set:
    word_set.remove(beginWord)

2、准备工作结束后,现在进入正式的编码操作。

# 下面这几步应该不用解释了吧?BFS模板,无脑写出来就行。

3ab166bf517c7fa66da7ae8ebc496d3e.png

写在最后。可能有的朋友会问了,你这个怎么这么慢呢,才打败30%?其实这是个误会,本题解已经尽量进行速度上的优化了,但是隔壁的双向BFS实在太强了,我们打不赢~

不过!不过!不过!之所以还是要写这篇文章,是因为这是很经典的图的BFS遍历模板,甚至只要微调一下就可以使用在同类型的题目中~

源码在此

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值