Given a pattern and a string str, find if strfollows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty substring in str.
Example 1:
Input: pattern ="abab", str ="redblueredblue"Output: true
Example 2:
Input: pattern = pattern ="aaaa", str ="asdasdasdasd"Output: true
Example 3:
Input: pattern ="aabb", str ="xyzabcxzyabc"Output: false
Notes:
You may assume both pattern and str contains only lowercase letters.
這道題是之前那道 Word Pattern 的拓展,之前那道題詞語之間都有空格隔開,這樣可以一個單詞一個單詞的讀入,然后來判斷是否符合給定的特征,而這道題沒有空格了,那么難度就大大的增加了,因為我們不知道對應的單詞是什么,所以得自行分開,可以用回溯法來生成每一種情況來判斷,這里還是需要用 HashMap 來建立模式字符和單詞之間的映射,還需要用變量p和r來記錄當前遞歸到的模式字符和單詞串的位置,在遞歸函數中,如果p和r分別等於模式字符串和單詞字符串的長度,說明此時匹配成功結束了,返回 ture,反之如果一個達到了而另一個沒有,說明匹配失敗了,返回 false。如果都不滿足上述條件的話,取出當前位置的模式字符,然后從單詞串的r位置開始往后遍歷,每次取出一個單詞,如果模式字符已經存在 HashMap 中,而且對應的單詞和取出的單詞也相等,那么再次調用遞歸函數在下一個位置,如果返回 true,那么就返回 true。反之如果該模式字符不在 HashMap 中,要看有沒有別的模式字符已經映射了當前取出的單詞,如果沒有的話,建立新的映射,並且調用遞歸函數,注意如果遞歸函數返回 false 了,要在 HashMap 中刪去這個映射,參見代碼如下:
解法一:
class Solution { public: bool wordPatternMatch(string pattern, string str) { unordered_map<char, string> m; return helper(pattern, 0, str, 0, m); } bool helper(string pattern, int p, string str, int r, unordered_map<char, string> &m) { if (p == pattern.size() && r == str.size()) return true; if (p == pattern.size() || r == str.size()) return false; char c = pattern[p]; for (int i = r; i < str.size(); ++i) { string t = str.substr(r, i - r + 1); if (m.count(c) && m[c] == t) { if (helper(pattern, p + 1, str, i + 1, m)) return true; } else if (!m.count(c)) { bool b = false; for (auto it : m) { if (it.second == t) b = true; } if (!b) { m[c] = t; if (helper(pattern, p + 1, str, i + 1, m)) return true; m.erase(c); } } } return false; } };
下面這種方法和上面那種方法很類似,不同點在於使用了 set,而使用其的原因也是為了記錄所有和模式字符建立過映射的單詞,這樣就不用每次遍歷 HashMap 了,只要在 set 中查找取出的單詞是否存在,如果存在了則跳過后面的處理,反之則進行和上面相同的處理,注意還要在 set 中插入新的單詞,最后也要同時刪除掉,參見代碼如下:
解法二:
class Solution { public: bool wordPatternMatch(string pattern, string str) { unordered_map<char, string> m; unordered_set<string> st; return helper(pattern, 0, str, 0, m, st); } bool helper(string pattern, int p, string str, int r, unordered_map<char, string> &m, unordered_set<string> &st) { if (p == pattern.size() && r == str.size()) return true; if (p == pattern.size() || r == str.size()) return false; char c = pattern[p]; for (int i = r; i < str.size(); ++i) { string t = str.substr(r, i - r + 1); if (m.count(c) && m[c] == t) { if (helper(pattern, p + 1, str, i + 1, m, st)) return true; } else if (!m.count(c)) { if (st.count(t)) continue; m[c] = t; st.insert(t); if (helper(pattern, p + 1, str, i + 1, m, st)) return true; m.erase(c); st.erase(t); } } return false; } };
再來看一種不寫 helper 函數的解法,可以調用自身,思路和上面的方法完全相同,參見代碼如下:
解法三:
class Solution { public: bool wordPatternMatch(string pattern, string str) { if (pattern.empty()) return str.empty(); if (m.count(pattern[0])) { string t = m[pattern[0]]; if (t.size() > str.size() || str.substr(0, t.size()) != t) return false; if (wordPatternMatch(pattern.substr(1), str.substr(t.size()))) return true; } else { for (int i = 1; i <= str.size(); ++i) { if (st.count(str.substr(0, i))) continue; m[pattern[0]] = str.substr(0, i); st.insert(str.substr(0, i)); if (wordPatternMatch(pattern.substr(1), str.substr(i))) return true; m.erase(pattern[0]); st.erase(str.substr(0, i)); } } return false; } unordered_map<char, string> m; unordered_set<string> st; };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/291
類似題目:
參考資料:
https://leetcode.com/problems/word-pattern-ii/
https://leetcode.com/problems/word-pattern-ii/discuss/73721/My-simplified-java-version
https://leetcode.com/problems/word-pattern-ii/discuss/73664/Share-my-Java-backtracking-solution
