[LeetCode] 問題系列 - Word Break + Word Search

寫這篇文章是因為word break和word search都很經(jīng)典。word search ii 還涉及到Trie。

Word Break

題目

給字符串s嘿辟,字典wordDict冒萄,判斷s能否用wordDict里的字符串組成。

例子

Input: s = "leetcode", wordDict = ["leet", "code"]
Output: true
Explanation: "leetcode" = "leet code".

方法

使用DP荔泳。dp[i]表示s.substring(0,i)是有效的蕉饼。i最多能取到s.length(),所以dp[] = new int[s.length() + 1]玛歌。
初始值dp[0] = true昧港,其實這個值怎么賦值在寫狀態(tài)轉(zhuǎn)移方程的時候能體現(xiàn)出來。
狀態(tài)轉(zhuǎn)移方程:dp[i] = dp[j] && wordDict.has(s.substring(j, i))支子。而j的取值范圍是[0,i)创肥。

代碼

    public boolean wordBreak(String s, List<String> wordDict) {
        boolean[] f = new boolean[s.length() + 1]; // 從[0,i)是valid
        f[0] = true;
        for (int i = 1; i <= s.length(); i++) { 
            // [0,i]能否被組成 取決于是否存在j,使得[0,j]true&substring[i,j]存在于dict中
            for (int j = 0; j < i; j++) {
                if (f[j] && wordDict.contains(s.substring(j, i))) {
                    f[i] = true; // f[s.length()] => [0,len)
                    break; // 退出里面的那個for loop
                }
            }
        }
        return f[s.length()];
    }

復雜度

時間復雜度:O(n^2)
空間復雜度:O(n)

Word Break II

題目

給字符串s,字典wordDict叹侄,返回所有組合方式巩搏。

例子

Input: s = "catsanddog", wordDict = ["cat", "cats", "and", "sand", "dog"]
Output:
[
"cats and dog",
"cat sand dog"
]

方法

使用DFS,但是使用一個memo table去記錄遇到并計算完的substring趾代。
為什么想到DFS:因為讓我們列出所有的解塔猾,一般列所有就需要窮舉,就是每種情況都找到稽坤。

代碼

class Solution {
    // 使用了memo table丈甸,可以變成dp問題
    // <任意的substring,這個substring可以用什么來組成>
    Map<String,List<String>> map = new HashMap<>(); 
    
    public List<String> wordBreak(String s, List<String> wordDict) {
        return dfs(s, new HashSet<>(wordDict));
    }
    
    // DFS 返回一個 list 包含從s中提取的所有substring
    // s的長度不斷縮小尿褪,知道為empty list睦擂,為最終狀態(tài)
    private List<String> dfs(String s, Set<String> wordDict) {
        if (map.containsKey(s)) {
            return map.get(s);
        }

        LinkedList<String> res = new LinkedList<String>();     
        if (s.length() == 0) {
            res.add("");
            return res;
        }               
        for (String word : wordDict) {
            if (s.startsWith(word)) {
                List<String> sublist = dfs(s.substring(word.length()), wordDict);
                for (String sub : sublist) {
                    res.add(word + (sub.isEmpty() ? "" : " ") + sub);               
                }
            }
        }       
        map.put(s, res);
        return res;
    }
}

Word Search

題目

給字符串word,看能不能搜到杖玲。

例子

board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
Given word = "ABCCED", return true.
Given word = "SEE", return true.
Given word = "ABCB", return false.

方法

使用DFS顿仇。

代碼

public class Solution {
    public boolean exist(char[][] board, String word) {
        if (board == null || board.length == 0 || word == null || word.length() == 0) {
            return false;
        }

        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == word.charAt(0)) {
                    if (judge(board, i, j, word, 0)) {
                        return true;
                    }
                }
            }
        }
        
        return false;
    }
    
    public boolean judge(char[][] board, int index1, int index2, String s, int indexS) {
        if (indexS >= s.length()) {
            return true;
        }
        if (index1 < 0 || index1 >= board.length || index2 < 0 || index2 >= board[0].length) {
            return false;
        }
        if (s.charAt(indexS) == board[index1][index2]) {
            char tmp = board[index1][index2]; // 類似visited
            board[index1][index2] = '*';
            if (judge(board, index1 + 1, index2, s, indexS + 1) 
                || judge(board, index1 - 1, index2, s, indexS + 1)
                || judge(board, index1, index2 + 1, s, indexS + 1)
                || judge(board, index1, index2 - 1, s, indexS + 1)) {
                return true;
            }
            board[index1][index2] = tmp;
        }
        return false;
    }
}

Word Search II

題目

給一堆字符串word,返回所有能搜到的字符串摆马。

例子

Input:
board = [
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
words = ["oath","pea","eat","rain"]
Output: ["eat","oath"]

方法

使用DFS+Trie臼闻。

代碼

class Solution {
    // 字典樹結點
    class TrieNode {
        public String val;
        public TrieNode[] child = new TrieNode[26];
        public boolean isLeaf = false;

        TrieNode(String val) {
            this.val = val;
        }
    }
    
    // 字典樹
    class Trie {
        public TrieNode root;
        
        Trie(TrieNode root) {
            this.root = root;
        }
        
        public void insert(String s) {
            TrieNode cur = root;
            for (char c : s.toCharArray()) {
                if (cur.child[c-'a'] == null) {
                    cur.child [c-'a'] = new TrieNode("");
                    cur = cur.child[c-'a'];
                } else {
                    cur = cur.child [c-'a'];
                }
            }
            cur.isLeaf = true;
            cur.val = s;
        }
    }
    
    public List<String> findWords(char[][] board, String[] words) {
        // 構建字典樹
        TrieNode root = new TrieNode("");
        Trie myTrie = new Trie(root);
        
        for (String s:words) {
            myTrie.insert(s);
        }

        // 使用set防止重復
        Set<String> result = new HashSet<>();
        int m = board.length;
        int n = board[0].length;
        boolean[][] visited = new boolean[m][n];
        
        // 遍歷整個二維數(shù)組,用DFS來遍歷所有可能存在在Trie里的排列組合
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                find(board, visited, i, j, result, root);
            }
        }
        
        return new LinkedList<String>(result);
    }
    private void find(char[][] board, boolean[][] visited, 
                      int i, int j, Set<String> result, TrieNode cur) {
        int m = board.length;
        int n = board[0].length;
        // 邊界以及是否已經(jīng)訪問判斷
        if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j]) {
            return;
        }
        cur = cur.child[board[i][j]-'a'];
        visited[i][j] = true;
        if (cur == null) {
            visited[i][j] = false; // 如果單詞不匹配囤采,回退
            return;
        }
        
        if (cur.isLeaf) { // 找到單詞加入
            result.add(cur.val); // 找到單詞后不能回退述呐,因為可能是“ad” “addd”這樣的單詞得繼續(xù)回溯
        }
        find(board, visited, i + 1, j, result, cur);
        find(board, visited, i, j + 1, result, cur);
        find(board, visited, i, j - 1, result, cur);
        find(board, visited, i - 1, j, result, cur);
        // 最后要回退,因為下一個起點可能會用到上一個起點的字符
        visited[i][j]=false;
    }
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蕉毯,一起剝皮案震驚了整個濱河市乓搬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌代虾,老刑警劉巖进肯,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異棉磨,居然都是意外死亡江掩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門乘瓤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來环形,“玉大人,你說我怎么就攤上這事馅扣≌遄” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵差油,是天一觀的道長拗军。 經(jīng)常有香客問我任洞,道長,這世上最難降的妖魔是什么发侵? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任交掏,我火速辦了婚禮,結果婚禮上刃鳄,老公的妹妹穿的比我還像新娘盅弛。我一直安慰自己,他們只是感情好叔锐,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布挪鹏。 她就那樣靜靜地躺著,像睡著了一般愉烙。 火紅的嫁衣襯著肌膚如雪讨盒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天步责,我揣著相機與錄音返顺,去河邊找鬼。 笑死蔓肯,一個胖子當著我的面吹牛遂鹊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔗包,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼秉扑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了气忠?” 一聲冷哼從身側(cè)響起邻储,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旧噪,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脓匿,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡淘钟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了陪毡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片米母。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖毡琉,靈堂內(nèi)的尸體忽然破棺而出铁瞒,到底是詐尸還是另有隱情,我是刑警寧澤桅滋,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布慧耍,位于F島的核電站身辨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏芍碧。R本人自食惡果不足惜煌珊,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泌豆。 院中可真熱鬧定庵,春花似錦、人聲如沸踪危。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贞远。三九已至敛滋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兴革,已是汗流浹背绎晃。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留杂曲,地道東北人庶艾。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像擎勘,于是被迫代替她去往敵國和親咱揍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355