LintCode刷题 123. 单词搜索

原题链接:

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语言趋于一致。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值