79. 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 =
[
[‘A’,’B’,’C’,’E’],
[‘S’,’F’,’C’,’S’],
[‘A’,’D’,’E’,’E’]
]
word = “ABCCED”, -> returns true,
word = “SEE”, -> returns true,
word = “ABCB”, -> returns false.
这道题目的意思是,给定一个字母表,和一串字母,之后判断能否用字母表中一连串相邻的字母来重现这串字符,其中,每个字母只能使用一次,不可重复使用。
其实仔细一看,这道题目其实是深度优先搜索的一个应用。
选择一个“结点”,之后访问该“结点”的邻结点,再访问邻结点的邻结点……直到找到对应字母串或者是无法找到为止。从思路上与深度优先搜索算法十分吻合。所以我们可以考虑使用递归,用深度优先的方法求解这道题。
我们遍历这个这个字母表,对每个字母调用findWord函数递归查找是否存在与word相同的一串相邻“结点”。
findWord函数接口:
bool findWord(vector<vector><char>>& board, int i, int j, string word, int index)
其中board是字符版,i和j分别为board的下标,word是目的字符串,index是标记当前正在比对string的第index个字符。
当当前节点的不存在(超出board范围)/已经访问过/与word的第index个字符不相同时,返回false,否则将标记该节点已被访问,之后对该节点相邻的四个节点(无论是否存在)进行递归查找,找到对应相邻节点串或是false返回。
同时,为了标记节点是否访问,我使用了一个二维布尔数组来标记每个节点是否被访问。改数组初始化为false。当确认board的当前值与word的当前值相同后,会标记为true,如果在递归检测返回false,也就是改点无法找到与word向匹配的相邻结点时,会将数组中的对应项再修改为false。
这样,当整个字符版与都搜索完毕之时,便能确实是否存在这样一串相邻结点,回答这个问题了。
以下是参考代码:
bool findWord(vector<vector<char>>& board, int i, int j, string word, int index);
bool isFound[500][500];
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
int high = board.size();
int length = board[0].size();
int wlength = word.length();
// 初始化isFound矩阵
for(int i = 0; i < 100; i++)
for(int j = 0; j < 100; j++)
isFound[i][j] = false;
for(int i = 0; i < high; i++) {
for(int j = 0; j < length; j++) {
if(findWord(board, i, j, word, 0))
return true;
}
}
return false;
}
};
bool findWord(vector<vector<char>>& board, int i, int j, string word, int index) {
if(index == word.length())
return true;
if(i < 0 || j < 0 || i >= board.size() || j >= board[0].size())
return false;
if(isFound[i][j] == true) {
return false;
}
isFound[i][j] = true;
if(board[i][j] != word[index]) {
isFound[i][j] = false;
return false;
}
bool e = findWord(board, i, j-1, word, index+1) ||
findWord(board, i, j+1, word, index+1) ||
findWord(board, i-1, j, word, index+1) ||
findWord(board, i+1, j, word, index+1);
if(e == false)
isFound[i][j] = false;
return e;
}
看了一下discuss,有一种更节约空间的方式——直接修改board的值,改成与原值、原board中完全无关的值(比如说使用异或),这样,当调用递归访问到已经使用过的结点时,由于值发生了改变并且完全无关,所以可以轻松去除直接返回false从而避免了递归访问了重复的元素。只要之后再次使用异或,便能够将其还原回原值了。这样就避免了因建立布尔数组储存访问情况占用了不少内存的问题了。