真是孤陋寡闻,直到前些时间才知道有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 有一个好处,提交的程序不通过,它会把测试不通过的测试数据告诉你,这样就方便调试了。构造测试用例真的很重要。