79. Word Search

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從而避免了遞歸訪問了重複的元素。只要之後再次使用異或,便能夠將其還原回原值了。這樣就避免了因建立布爾數組儲存訪問情況佔用了不少內存的問題了。

發佈了30 篇原創文章 · 獲贊 1 · 訪問量 3810
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章