原题链接:
https://www.lintcode.com/zh-cn/problem/word-search/
题目描述
给出一个二维的字母板和一个单词,寻找字母板网格中是否存在这个单词。
单词可以由按顺序的相邻单元的字母组成,其中相邻单元指的是水平或者垂直方向相邻。每个单元中的字母最多只能使用一次。
样例
给出board =
[
"ABCE",
"SFCS",
"ADEE"
]
word = "ABCCED", ->返回 true,
word = "SEE",-> 返回 true,
word = "ABCB", -> 返回 false.
题目解析
本题看样例还是比较容易理解的。题目给出了一个二维数组(实际上题目想给出的是一个一维的字符串数组,一个数组里面有很多个字符串)和一个单词(字符串来的),问:这个二维数组是否能组成一个这样的字符串。
新字符串的组成方式是,从二维数组中随便一个位置开始,向上下左右四个方向取字符,直到取到到跟题目给出的字符串相同的字符串为止。
题目还有一个限制,就是一个字符只能用一次。
思路
这题要用递归回溯法。
首先从二维数组里面查找,找到一个跟word字符串的首字母相同的字母。然后从这个字母为出发点,向上下左右四个方向查找,查找到跟word的第二个字母相同的字母,然后再从取到的第二个字母的位置开始,向上下左右查找,查找到跟word的第三个字母相同的字母,再从第三个字母的位置开始......直到查找到跟word的最后一个字母相同的字母,那么就认为该二维数组按照题目的规则能够组成word这个字符串。
所以显然用递归解答比较好。 这里还有几个问题需要注意:
1.刚开始从数组中遍历word的首字母,遍历到第一个与word的首字母相同的字符之后,如果不能组成跟word相同的字符串,那么还需要继续查找。因为数组里面可能会有多个跟word首字符相同的字母。
2.由于数组中的每个字母只能用一次,所以用了之后需要设置标识,下次不能再用。设置标识之后,要在适当的位置进行回溯,还原标志位。
代码(Python)
class Solution:
"""
@param board: A list of lists of character
@param word: A string
@return: A boolean
"""
def exist(self, board, word):
if not board:
return False
#设置可用标志位。可用为True,不可用(证明这个值已经用过了)为False
boardValid = []
for i in range(len(board)):
boardValid.append([])
for j in range(len(board[i])):
boardValid[i].append(True)
#循环遍历,如果跟word首字母,则开始判断
for i in range(len(board)):
for j in range(len(board[i])):
#如果跟word首字母,则开始判断
if word[0] == board[i][j]:
# print "boardValid=",boardValid
exist = self.isExist(board, word,i,j,0,boardValid)
if exist:
return True
return False
"""
自定义方法:board中是能组成在word的从第hasLength个元素开始的下几个元素
@param board: A list of lists of character
@param word: A string
@param i: board中当前位置的横坐标
@param j: board中当前位置的纵坐标
@param hasLength: 当前已经取得的结果的长度
@param boardValid: 表示board中元素是否可用的一个数组
@return: A boolean
"""
def isExist(self, board, word, i ,j , hasLength, boardValid):
# print "hasLength=",hasLength
#长度足够
if hasLength == len(word):
return True
#超出范围
if i<0 or j<0 or i>=len(board) :
return False
#超出范围
if j>=len(board[i]):
return False
#判断是否可用
if boardValid[i][j] == False:
return False
#判断字母是否相等
if word[hasLength] != board[i][j]:
return False
#设置标志位
boardValid[i][j] = False
#上下左右
leftExist = self.isExist(board, word,i-1,j,hasLength+1,boardValid);
rightExist = self.isExist(board, word,i+1,j,hasLength+1,boardValid);
upExist = self.isExist(board, word,i,j-1,hasLength+1,boardValid);
downExist = self.isExist(board, word,i,j+1,hasLength+1,boardValid);
if leftExist or rightExist or upExist or downExist:
return True
else:
#来到这里,证明上下左右都没使用到这个值,需要恢复。否则以后拿不到这个值
boardValid[i][j] = True
return False
复制代码
谦言忘语
个人目前只懂一丁点python语法,所以不做语法上的优化,而且整体代码风格效果会尽量跟C语言趋于一致。