问题
原问题网页:Boggle
问题大致描述如下:
有一个 4 × 4 4\times4 4×4 的方格图,每一个格子上标有一个英文字母,现要从中寻找出英文单词。
规则如下:
- 该单词由一系列 相邻 的格子组成。这里的相邻指上下左右和对角
- 该单词长度至少为3
- 每一个格子只能用一次
- 该单词必须在一个预先给定的字典集内
然后按每一个单词的长度进行计分
该问题要在给定一个单词集合一个字母网格的前提下,给出所有符合条件的单词,以及计算它们的分数之和。
思路
首先要存储字典集和字母网格的数据。这里采用字典树来存储字典集,字典树可以快速地查找某个单词是否在该字典集中。用一个Boggleboard类来存储字母网格,在Boggleboard类中用一个二维数组来存储网格上的字母,定义neighbours方法,来计算 ( i , j ) (i,j) (i,j) 位置处的相邻网格,以便接下来搜索使用。
利用深度优先搜索(Depth-First-Search)来搜索所有可能的单词。先定义节点node类,用来存储访问过的网格和当前所形成的字符串。每次从一个网格点出发,以该网格点为当前节点,进行深度优先搜索。如果该节点的当前字符串长度大于2且在预先给定的字典集中,那么就将其加入到有效单词集中,然后对于该网格的每一个neighbour,如果没有访问过这个neighbour,那就以这个neighbour为当前节点,更新访问集和当前字符串,然后递归进行搜索。
这样运行起来时间较长,可以在每次深度优先搜索的时候,进行一个判断:如果节点的当前字符串不是单词集的前缀,即单词集中的单词没有以该字符串开头的,那么就不用再进行搜索了,因为以该字符串开头的单词,肯定不在单词集里面,这样可以提高搜索的效率。
代码
# -*- coding: utf-8 -*-
""" Created on Sun Jan 10 15:04:57 2021 @author: zxw """
# 设置文件路径
import os
os.chdir('C:/Users/zxw/Desktop/修身/与自己/数据科学/算法/boggle')
# 参考https://blog.csdn.net/weixin_43204128/article/details/90633128
# 字典树
class Trie:
def __init__(self):
self.root = {
} # 这里用一个字典存储
self.end_of_word = '#' # 用#标志一个单词的结束
def insert(self, word: str):
node = self.root
for char in word:
node = node.setdefault(char, {
})
node[self.end_of_word] = self.end_of_word
# 查找一个单词是否完整的在字典树里,所以最后一句判断node是否等于#
def search(self, word: str):
node = self.root
for char in word:
if char not in node:
return False
node = node[char]
return self.end_of_word in node
# 查找是否有一个单词是这个前缀开始的
def startsWith(self, prefix: str):
node = self.root
for char in prefix:
if char not in node:
return False
node = node[char]
return True
# 建立Board类
class BoggleBoard:
def __init__(self,boardname):
with open(boardname,'r') as f:
t = f.readlines()
self.rows = int(t[0].strip().split()[0])
self.cols = int(t[0].strip().split()[1])
self.Boggle = [[j for j in t[i+1].strip().split()] for i in range(self.rows)]
def getLetter(self,i,j):
return self.Boggle[i][j]
# 每一个格子的邻居
def neighbours(self,i,j):
r = self.rows
c = self.cols
nghb = []
if i != 0:
nghb.append([i-1,j])
if i != r-1:
nghb.append([i+1,j])
if j != 0:
nghb.append([i,j-1])
if j != c-1:
nghb.append([i,j+1])
if (i != 0) & (j != 0):
nghb.append([i-1,j-1])
if (i != 0) & (j != c-1):
nghb.append([i-1,j+1])
if (i != r-1) & (j != 0):
nghb.append([i+1,j-1])
if (i != r-1) & (j != c-1):
nghb.append([i+1,j+1])
return nghb
# 定义深度优先搜索的节点
class node:
def __init__(self,board,i,j):
self.visited = set() # 已访问过的点
self.index = (i,j)
self.nghb = [k for k in board.neighbours(i,j)]
if board.Boggle[i][j] == 'Qu': #Qu情况的特殊处理
self.char = 'QU'
else:
self.char = board.Boggle[i][j]
class BoggleSolver:
def __init__(self, dictionary):
self.dictionary = dictionary
self.ValidWords = set()
# 深度优先搜索
def dfs(self,Node, board):
Node.visited.add(Node.index)
# 若没有以当前字符串开头的单词,则跳过搜索
if not self.dictionary.startsWith(Node.char):
pass
else:
# 如果字符串长度大于2且在字典中,则加入有效集
if len(Node.char) > 2:
if self.dictionary.search(Node.char):
self.ValidWords.add(Node.char)
# 递归搜索其没有到达过的邻居
for k in Node.nghb:
node_k = node(board,k[0],k[1])
if node_k.index not in Node.visited:
node_k.visited = Node.visited
node_k.char = Node.char + node_k.char
self.dfs(node_k,board)
Node.visited.remove(Node.index) # !!!
# 获得所有有效单词
def getAllValidWords(self, board):
self.ValidWords = set()
r = board.rows
c = board.cols
for i in range(r):
for j in range(c):
self.dfs(node(board, i, j),board)
return self.ValidWords
# 计算每个单词所对应的分数
def scoreOf(self, word):
if self.dictionary.search(word):
if (len(word) == 3)|(len(word) == 4):
return 1
elif len(word) == 5:
return 2
elif len(word) == 6:
return 3
elif len(word) == 7:
return 5
elif len(word) > 7:
return 11
return 0
# 获得所有单词分数之和
def Allscores(self):
score = 0
for word in self.ValidWords:
score = score + self.scoreOf(word)
return score
# 测试
if __name__ == '__main__':
dictionary = Trie()
dict_name = 'dictionary-yawl.txt' #设置字典集
with open(dict_name,'r') as f:
t = f.readlines()
for i in t:
dictionary.insert(i.strip())
boardname = 'board-points26539.txt' # 设置Board
test_board = BoggleBoard(boardname)
test_solver = BoggleSolver(dictionary)
test_solver.getAllValidWords(test_board)
test_solver.Allscores()
结果
总结
这次作业主要涉及以下内容:
- 利用字典树存储字典集
- 利用深度优先搜索递归搜索所有可能情况
今天的文章普林斯顿算法课作业 part II 的python实现(四)Boggle分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/62439.html