【Leetcode】676. Implement Magic Dictionary

題目地址:

https://leetcode.com/problems/implement-magic-dictionary/

要求實現一個數據結構,可以實現:
1、添加字符串;
2、給定一個字符串ss,在數據結構中搜索是否存在某個字符串,和ss長度相等,並且恰好相差11個字符。

法1:哈希表。直接把所有字符串存進一個哈希表。在search的時候直接搜索是否存在某個單詞滿足條件。代碼如下:

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class MagicDictionary {
    
    private Set<String> set;
    
    /** Initialize your data structure here. */
    public MagicDictionary() {
        set = new HashSet<>();
    }
    
    /** Build a dictionary through a list of words */
    public void buildDict(String[] dict) {
        set.addAll(Arrays.asList(dict));
    }
    
    /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */
    public boolean search(String word) {
        int changed = 0;
        for (String s : set) {
        	// 長度如果不等就直接略過
            if (s.length() != word.length()) {
                continue;
            }
            // changed記錄有多少個字符改變過了
            changed = 0;
            for (int i = 0; i < word.length(); i++) {
            	// 如果發現有字符不等,就計入changed
                if (s.charAt(i) != word.charAt(i)) {
                    changed++;
                }
                // 如果changed大於等於2,說明至少要改變兩個字符,直接跳出循環,略過該字符串
                if (changed >= 2) {
                    break;
                }
            }
            // 如果changed等於1,說明找到了一個字符串和word只差一個字符,返回true
            if (changed == 1) {
                return true;
            }
        }
       	// 若未找到返回false 
        return false;
    }
}

search時間複雜度O(nl)O(nl)

法2:Trie + DFS。添加單詞和Trie一模一樣。搜索單詞的時候需要用DFS,同時將已經改變了多少字符作爲參數在遞歸的時候傳遞下去。代碼如下:

public class MagicDictionary {
    
    class Node {
        boolean isWord;
        Node[] next;
        Node() {
            next = new Node[26];
        }
    }
    
    private Node root;
    
    /** Initialize your data structure here. */
    public MagicDictionary() {
        root = new Node();
    }
    
    /** Build a dictionary through a list of words */
    public void buildDict(String[] dict) {
        for (String word : dict) {
            insert(word);
        }
    }
    
    private void insert(String word) {
        Node cur = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (cur.next[c - 'a'] == null) {
                cur.next[c - 'a'] = new Node();
            }
            cur = cur.next[c - 'a'];
        }
        
        cur.isWord = true;
    }
    
    /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */
    public boolean search(String word) {
        return dfs(root, word, 0, 0);
    }
    // 在cur爲根的子樹裏,從word[start]開始找有沒有滿足條件的單詞。changed指的是已經使用過改變字符的機會
    private boolean dfs(Node cur, String word, int start, int changed) {
    	// 如果已經用完了一次改變字符的機會,則直接返回false
        if (changed >= 2) {
            return false;
        }
        // 如果搜到了word末尾了,則看看是否當前節點被標記爲單詞末尾,並且是否剛好用了一次改變字符的機會
        if (start == word.length()) {
            return changed == 1 && cur.isWord;
        }
        
        char c = word.charAt(start);
        if (cur.next[c - 'a'] != null) {
        	// 如果cur下面剛好有一個分支是c這個字符,那麼分成兩種情況考慮:
        	// 如果不改變這個字符,能發現合法字符串則返回true,此時changed參數不變;
        	// 如果改變這個字符,那麼就要從下一個不等於c的分叉開始找起,並將changed加1;
            if (dfs(cur.next[c - 'a'], word, start + 1, changed)) {
                return true;
            }
            for (int i = 0; i < cur.next.length; i++) {
                if (i != c - 'a' && cur.next[i] != null && dfs(cur.next[i], word, start + 1, changed + 1)) {
                    return true;
                }
            }
        } else {
        	// 如果cur下面沒有分支是c這個字符,那麼當前字符必須修改
        	// 如果已經消耗了一次修改機會了,則直接返回false
            if (changed >= 1) {
                return false;
            }
    		// 否則遍歷所有分叉進行DFS,並且將本次修改次數計入changed
            for (int i = 0; i < cur.next.length; i++) {
                if (cur.next[i] != null && dfs(cur.next[i], word, start + 1, changed + 1)) {
                    return true;
                }
            }
        }    
        // 上面已經把所有可能能找到合法字符串的情況都枚舉過了,如果還沒找到合法字符串,則返回false
        return false;
    } 
}

時空複雜度一樣。其中空間複雜度還要看具體有哪些字符串。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章