Leetcode - Word Search

My code:

import java.util.HashSet;

public class Solution {
    private int width = 0;
    private int height = 0;
    public boolean exist(char[][] board, String word) {
        if (board == null)
            return false;
        if (board.length == 0)
            return false;
        if (word == null || word.length() == 0)
            return false;
        width = board[0].length;
        height = board.length;
        HashSet<Integer> isVisited = new HashSet<Integer>();
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                boolean ret = helper(i, j, 0, board, word, isVisited);
                if (ret)
                    return true;
            }
        }
        return false;
    }
    
    private boolean helper(int i, int j, int begin, char[][] board, String word, HashSet<Integer> isVisited) {
        if (!isValid(i, j, isVisited))
            return false;
        if (board[i][j] != word.charAt(begin))
            return false;
        if (begin == word.length() - 1)
            return true;
        isVisited.add(i * width + j);
        if (helper(i - 1, j, begin + 1, board, word, isVisited))
            return true;
        if (helper(i + 1, j, begin + 1, board, word, isVisited))
            return true;
        if (helper(i, j - 1, begin + 1, board, word, isVisited))
            return true;
        if (helper(i, j + 1, begin + 1, board, word, isVisited))
            return true;
        isVisited.remove(i * width + j);
        return false;
    }
    
    /**
     * detect whether this location in array is valid. If it is visited, it is invalid
     * @param i row
     * @param j col
     * @param isVisited boolean[][]
     * @return whether it is valid
     */
    private boolean isValid(int i, int j, HashSet<Integer> isVisited) {
        if (i < 0 || i >= height)
            return false;
        if (j < 0 || j >= width)
            return false;
        return !isVisited.contains(i * width + j);
    }
    
    public static void main(String[] args) {
        char[][] board = new char[3][4];
        board[0][0] = 'A';
        board[0][1] = 'B';
        board[0][2] = 'C';
        board[0][3] = 'E';
        
        board[1][0] = 'S';
        board[1][1] = 'F';
        board[1][2] = 'C';
        board[1][3] = 'S';
        
        board[2][0] = 'A';
        board[2][1] = 'D';
        board[2][2] = 'E';
        board[2][3] = 'E';
        
        Solution test = new Solution();
        System.out.println(test.exist(board, "ADFA"));
    }
}

總算是過(guò)了測(cè)試完丽。一開始我是用一個(gè),
boolean[][] isVisited 數(shù)組來(lái)做的拇舀。然后每次遞歸逻族,為了避免重復(fù)訪問(wèn)同一個(gè)元素,我都需要把原布爾數(shù)組拷貝一份傳入下層遞歸骄崩。四個(gè)方向聘鳞,上下左右,都需要拷貝一下原數(shù)組要拂。當(dāng)原數(shù)組無(wú)比巨大時(shí)抠璃,而我的每一次遞歸又都需要拷貝四次原數(shù)組,導(dǎo)致我的時(shí)間測(cè)試過(guò)不了脱惰。我在八皇后問(wèn)題中就是用這個(gè)辦法做的搏嗡,現(xiàn)在看來(lái)不是很好,或者說(shuō)拉一,很糟糕采盒。因?yàn)閿?shù)組只是很少的一部分發(fā)生了改變,但我需要重新拷貝整個(gè)數(shù)組蔚润。很像是 meng project 中的bitmap, 浪費(fèi)了大量的內(nèi)存磅氨。
然后我換用了一個(gè)HashSet<Integer>, 每次把對(duì)應(yīng)位置的i,j轉(zhuǎn)換為一個(gè)特定的index存入hash set嫡纠。
之后再刪除烦租。避免了布爾數(shù)組的問(wèn)題并且可以達(dá)到相同的效果延赌。
于是,過(guò)了測(cè)試叉橱。但是時(shí)間仍然很高挫以。
然后我看了答案。
發(fā)現(xiàn)赏迟,我的HashSet在遞歸前插入元素屡贺,遞歸后刪除元素的做法可以再簡(jiǎn)化蠢棱。
遞歸前锌杀,設(shè)置該元素為board[i][j] = '#', 因?yàn)?#不是字母,所以以后的深層遞歸是無(wú)法訪問(wèn)到他的泻仙。
遞歸后糕再,再把他改回來(lái),不要影響其他循環(huán)下的遞歸玉转。

代碼如下:

public class Solution {
    private int width = 0;
    private int height = 0;
    public boolean exist(char[][] board, String word) {
        if (board == null)
            return false;
        if (board.length == 0)
            return false;
        if (word == null || word.length() == 0)
            return false;
        width = board[0].length;
        height = board.length;
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                boolean ret = helper(i, j, 0, board, word);
                if (ret)
                    return true;
            }
        }
        return false;
    }
    
    private boolean helper(int i, int j, int begin, char[][] board, String word) {
        if (i < 0 || i >= height || j < 0 || j >= width)
            return false;
        if (board[i][j] != word.charAt(begin))
            return false;
        char temp = board[i][j];
        board[i][j] = '#';
        if (begin == word.length() - 1)
            return true;
        if (helper(i - 1, j, begin + 1, board, word))
            return true;
        if (helper(i + 1, j, begin + 1, board, word))
            return true;
        if (helper(i, j - 1, begin + 1, board, word))
            return true;
        if (helper(i, j + 1, begin + 1, board, word))
            return true;
        board[i][j] = temp;
        return false;
    }
    
    public static void main(String[] args) {
        char[][] board = new char[3][4];
        board[0][0] = 'A';
        board[0][1] = 'B';
        board[0][2] = 'C';
        board[0][3] = 'E';
        
        board[1][0] = 'S';
        board[1][1] = 'F';
        board[1][2] = 'C';
        board[1][3] = 'S';
        
        board[2][0] = 'A';
        board[2][1] = 'D';
        board[2][2] = 'E';
        board[2][3] = 'E';
        
        Solution test = new Solution();
        System.out.println(test.exist(board, "ADFA"));
    }
}

http://www.programcreek.com/2014/06/leetcode-word-search-java/

思想其實(shí)一直沒變過(guò)突想。就是dfs, 不停地往深層遞歸。就是八皇后問(wèn)題究抓。
這類問(wèn)題的統(tǒng)一思想就是猾担,
知道最終的目的是什么,確定停止條件刺下。即什么時(shí)候返回true绑嘹,不再往下遞歸。
然后橘茉,每次遞歸的時(shí)候工腋,往上下左右各個(gè)方向擴(kuò)散,并且判斷這些擴(kuò)散的方向是否有效畅卓。他們是否越界了擅腰?
他們是否之前已經(jīng)被訪問(wèn)過(guò)了。
如果判斷之前是否被訪問(wèn)過(guò)了翁潘,最簡(jiǎn)單的做法就是布爾數(shù)組趁冈,然后再每次深層遞歸時(shí)重新拷貝一份傳進(jìn)去。
但完全可以用HashSet<Integer> 來(lái)代替拜马,免去了拷貝的過(guò)程渗勘,節(jié)約了大量的時(shí)間。
然后這道題目告訴我們還可以再簡(jiǎn)化一膨。
將該元素設(shè)置為一個(gè)不滿足再次深層遞歸條件的元素呀邢。這樣,深層遞歸時(shí)再次訪問(wèn)到該元素時(shí)會(huì)自動(dòng)停止豹绪。這樣就避免了HashSet操作所帶來(lái)的消耗价淌。遞歸結(jié)束后申眼,再將該元素恢復(fù)到原來(lái)的值,避免影響其他循環(huán)中的遞歸蝉衣。

for (int i = 0; i < height; i++)
    for (int j = 0; j < width; j++)
           helper(...);  // recursive function

**
Anyway, Good luck, Richardo!
**

My code:

public class Solution {
    int row = 0;
    int col = 0;
    public boolean exist(char[][] board, String word) {
        if (board == null || board.length == 0 || board[0].length == 0 || word == null || word.length() == 0) {
            return false;
        }
        
        row = board.length;
        col = board[0].length;
        boolean[][] isVisited = new boolean[row][col];
        
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                isVisited[i][j] = true;
                boolean flag = helper(0, word, i, j, board, isVisited);
                isVisited[i][j] = false;
                if (flag) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    private boolean helper(int position, String word, int i, int j, char[][] board, boolean[][] isVisited) {
        if (position == word.length() - 1) {
            char curr = word.charAt(position);
            if (curr == board[i][j]) {
                return true;
            }
            else {
                return false;
            }
        }
        else {
            char curr = word.charAt(position);
            if (curr == board[i][j]) {
                if (isValid(i + 1, j) && !isVisited[i + 1][j]) {
                    isVisited[i + 1][j] = true;
                    boolean flag = helper(position + 1, word, i + 1, j, board, isVisited);
                    isVisited[i + 1][j] = false;
                    if (flag)
                        return flag;
                }
                if (isValid(i - 1, j) && !isVisited[i - 1][j]) {
                    isVisited[i - 1][j] = true;
                    boolean flag = helper(position + 1, word, i - 1, j, board, isVisited);
                    isVisited[i - 1][j] = false;
                    if (flag)
                        return flag;
                }
                if (isValid(i, j + 1) && !isVisited[i][j + 1]) {
                    isVisited[i][j + 1] = true;
                    boolean flag = helper(position + 1, word, i, j + 1, board, isVisited);
                    isVisited[i][j + 1] = false;
                    if (flag)
                        return flag;
                }
                if (isValid(i, j - 1) && !isVisited[i][j - 1]) {
                    isVisited[i][j - 1] = true;
                    boolean flag = helper(position + 1, word, i, j - 1, board, isVisited);
                    isVisited[i][j - 1] = false;
                    if (flag)
                        return flag;
                }
                return false;
            }
            else {
                return false;
            }
        }
    }
    
    private boolean isValid(int i, int j) {
        if (i >= 0 && i < row && j >= 0 && j < col) {
            return true;
        }
        else {
            return false;
        }
    }
    
}

這道題目就是dfs,體力活括尸。沒什么難度。

Anyway, Good luck, Richardo! -- 09/02/2016

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末病毡,一起剝皮案震驚了整個(gè)濱河市濒翻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌啦膜,老刑警劉巖有送,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異僧家,居然都是意外死亡雀摘,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門八拱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)阵赠,“玉大人,你說(shuō)我怎么就攤上這事肌稻∏迨矗” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵爹谭,是天一觀的道長(zhǎng)枷邪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)旦棉,這世上最難降的妖魔是什么齿风? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮绑洛,結(jié)果婚禮上救斑,老公的妹妹穿的比我還像新娘。我一直安慰自己真屯,他們只是感情好脸候,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绑蔫,像睡著了一般运沦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上配深,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天携添,我揣著相機(jī)與錄音,去河邊找鬼篓叶。 笑死烈掠,一個(gè)胖子當(dāng)著我的面吹牛羞秤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播左敌,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼瘾蛋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了矫限?” 一聲冷哼從身側(cè)響起哺哼,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叼风,沒想到半個(gè)月后取董,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咬扇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年甲葬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了廊勃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懈贺。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖坡垫,靈堂內(nèi)的尸體忽然破棺而出梭灿,到底是詐尸還是另有隱情,我是刑警寧澤冰悠,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布堡妒,位于F島的核電站,受9級(jí)特大地震影響溉卓,放射性物質(zhì)發(fā)生泄漏皮迟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一桑寨、第九天 我趴在偏房一處隱蔽的房頂上張望伏尼。 院中可真熱鬧,春花似錦尉尾、人聲如沸爆阶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辨图。三九已至,卻和暖如春肢藐,著一層夾襖步出監(jiān)牢的瞬間故河,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工吆豹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鱼的,地道東北人杉女。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鸳吸,于是被迫代替她去往敵國(guó)和親熏挎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • My code: reference:https://discuss.leetcode.com/topic/332...
    Richardo92閱讀 604評(píng)論 0 0
  • 從周日開始做real time vision 做到了周二晌砾,然后周三一整天被老板壓迫工作到晚上10點(diǎn)半T^T 1點(diǎn)多...
    98Future閱讀 684評(píng)論 0 0
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問(wèn)題, 分享了一些自己做題目的經(jīng)驗(yàn)坎拐。 張土汪:刷leetcod...
    土汪閱讀 12,748評(píng)論 0 33
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法养匈,內(nèi)部類的語(yǔ)法哼勇,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法呕乎,線程的語(yǔ)...
    子非魚_t_閱讀 31,664評(píng)論 18 399
  • 用于拼接地址的常量直接上代碼积担,這塊代碼是封裝在NetAddressFile.swift類中 以下代碼是NetWor...
    玩伴_Cocoa閱讀 2,564評(píng)論 6 3