[LeetCode] Word Search 的非递归实现

真是孤陋寡闻,直到前些时间才知道有LeetCode这么一个网站。这段时间我正好也在复习数据结构,这样可以用这些题来检验一下学习效果。就从Array分类的Word Search问题开始吧。

Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.
For example,
Given board =[
  ["ABCE"],
  ["SFCS"],
  ["ADEE"]
]
word = "ABCCED", -> returns true,
word = "SEE", -> returns true,
word = "ABCB", -> returns false.

思路还是很容易想到的,先通过二重循环找到地一个字母的位置,然后做深度优先搜索(4个方向),参照书上深度优先搜索的递归实现,改一改,调试调试,就通过了。源码如下

class Solution(object):
    
    def __init__(self):
        self._next = [(1,0),(0,1),(-1,0),(0,-1)]
        
    def _dfs(self, x, y):
        if self._flag == True:
            return
        if self._count == len(self._word):
            self._flag = True 
            return
        for i in range(4):
            tx, ty = x + self._next[i][0], y + self._next[i][1]
            if 0<=tx<self._row and 0<=ty<self._col and \
            self._visited[tx][ty] == 0 and \
            self._board[tx][ty] == self._word[self._count]:
                self._visited[tx][ty] = 1
                self._count += 1
                self._dfs(tx,ty)
                self._count -= 1
                self._visited[tx][ty] = 0
                 
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        
        self._row = len(board)                                  #row
        self._col = len(board[0])                               #col
        self._visited = [[0 for j in range(self._col) ] for i in range(self._row) ]   
        self._board = board
        self._word = word
        
        self._count = 0     
        self._flag = False              
        
        for row in range(self._row):
            for col in range(self._col):
                if self._board[row][col] == self._word[0]:
                    self._visited[row][col] = 1
                    self._count = 1
                    self._dfs(row,col)
                    if self._flag == True:
                        return True   
                                     
                    self._visited[row][col] = 0
                    self._count = 0
        return False

if __name__ == '__main__':
    s = Solution()
    
    board = ["ABCE","SFES","ADEE"]
    word = "ABCESEEEFS"
    print s.exist(board,word)
    
    board = ["ABCE","SFCS","ADEE","ADEE","ADEE","ADEE"]
    word =  "ABCS"
    print s.exist(board,word)
因正好在看堆栈相关的内容,所以想用非递归来实现。原来以为能够比较轻松搞定,结果确实比较狼狈,反反复复,把周六、周日都搭上了,最后总算通过。收获是通过这个程序把一些原来没有弄得很清楚的地方理清楚了。即什么时候入栈,什么时候出栈,把什么东西放到堆栈里。对应这个问题,就是什么时候向前走(深度优先),什么时候回退( backtrace),回退到哪一步。

入栈的内容:[x, y, steps ],其中x, y是当前满足要求的节点的坐标,steps是一个列表,存放与(x,y)的四个方向上的邻居节点,前提是这些邻居节点是下一个满足要求的字母。如果没有满足邻居节点,则steps为空,则出栈;如果不为空,则从steps.pop()一个(tx, ty)出来判断,如果(tx, ty)有符合要求邻居节点的则(tx, ty)如站,否则继续从steps.pop(),然后继续判断;如果直到堆栈为空,还没有找到,则返回False,找到返回True。找的过程中必须标记以访问的点,这些点不能再次访问,否则重复了。

代码如下:

class Solution(object):
    
    def _push(self, e):  
           self._stack.append(e)  
       
    def _pop(self):  
        if len(self._stack)>0:  
            return self._stack.pop()    #remove last item from list  
        else:
            return None
        
    def _top(self):
        if len(self._stack)>0:  
            return self._stack[-1]                    
        else:
            return None
    
    def _dfs(self, x, y):
        
        if x<0 or y<0:
            return False
        
        if self._word[0] == self._board[x][y]:
            self._visited[x][y] = 1
            self._count = 1
            if self._count == len(self._word):
                return True
            
            steps = []
            for i in range(3, -1, -1):
                tx,  ty  = x + self._next[i][0],  y + self._next[i][1]
                if 0<= tx < self._row and 0<= ty < self._col and \
                self._visited[tx][ty] == 0 and \
                self._word[self._count] == self._board[tx][ty]:
                    #self._visited[tx][ty] = 1
                    steps.append((tx,ty))    
            self._push([x,y,steps])
           
            #print '---'
            
        else:
            return False
        
        while self._top() != None:
            #print self._stack
            #print self._count
            e = self._top()
            x, y, steps = e[0], e[1], e[2]
            if len(steps) == 0:               #backtrace
                self._visited[x][y] = 0
                self._count -= 1
                self._pop()
            else:                             #forward  
                x, y = steps.pop()
                #if self._word[self._count] == self._board[x][y]:
                self._count += 1
                self._visited[x][y] = 1
                    
                if self._count == len(self._word):
                    return True
                else:
                    tsteps = []
                    for i in range(3, -1, -1):
                        tx,  ty  = x + self._next[i][0],  y + self._next[i][1]
                        if 0<= tx < self._row and 0<= ty < self._col and \
                        self._visited[tx][ty] == 0 and \
                        self._word[self._count] == self._board[tx][ty]:
                            #self._visited[tx][ty] = 1
                            tsteps.append((tx,ty))
                            
                    if len(tsteps) == 0:                 #backtrace
                        self._visited[x][y] = 0
                        self._count -= 1
                    else:
                        self._push([x,y,tsteps])         #forward
        return False
            
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        
        self._next = [(1,0),(0,1),(-1,0),(0,-1)]
        self._row = len(board)                                #row
        self._col = len(board[0])                             #col
        self._visited = [[0 for j in range(self._col) ] for i in range(self._row) ]   
        self._board = board
        self._word = word
        
        self._stack = []                                      #the stack  
        self._count = 0                          
                    
        for x in range(self._row):
            for y in range(self._col):
                self._count = 0 
                if self._board[x][y] == self._word[0]:
                    if self._dfs(x,y) :
                        return True
        return False

if __name__ == '__main__':
    
    s = Solution()
    
    board = ["ABCE","SFES","ADEE"]
    #word = "ABCESEEEFS"
    word = 'ABCESEEEFS'
    print s.exist(board,word)
    
    board = ["ABCE123456","SFCS123456","ADEE123456","ADEE123456","ADEE123456","ADEE123456"]
    word =  "ABCB"
    print s.exist(board,word)
      
    word =  "ABCA"
    print s.exist(board,word)
      
    board = ["ABCE","SFCS","ADEE"]
      

LeetCode 有一个好处,提交的程序不通过,它会把测试不通过的测试数据告诉你,这样就方便调试了。构造测试用例真的很重要。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值