題目地址:
https://leetcode.com/problems/implement-magic-dictionary/
要求實現一個數據結構,可以實現:
1、添加字符串;
2、給定一個字符串,在數據結構中搜索是否存在某個字符串,和長度相等,並且恰好相差個字符。
法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
時間複雜度。
法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;
}
}
時空複雜度一樣。其中空間複雜度還要看具體有哪些字符串。