演算法:單詞匹配290. Word Pattern
技術標籤:演算法leetcodeword pattern模式匹配
LeetCode全集請參考:LeetCode Github 大全
題目
Given a pattern and a string s, find if s follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in s.
Example 1:
Input: pattern = "abba", s = "dog cat cat dog"
Output: true
Example 2:
Input: pattern = "abba", s = "dog cat cat fish"
Output: false
Example 3:
Input: pattern = "aaaa", s = "dog cat cat dog"
Output: false
Example 4:
Input: pattern = "abba", s = "dog dog dog dog"
Output: false
Constraints:
- 1 <= pattern.length <= 300
- pattern contains only lower-case English letters.
- 1 <= s.length <= 3000
- s contains only lower-case English letters and spaces ’ '.
- s does not contain any leading or trailing spaces.
- All the words in s are separated by a single space.
方法一
方法1:兩個雜湊圖
錯誤的直覺:
開始思考此問題的最幼稚的方法是擁有一個雜湊表,跟蹤哪個字元(pattern)對映到哪個單詞(s)。當您掃描每個字元-單詞對時,請更新此雜湊對映以查詢對映中未包含的字元。如果看到已經是對映鍵之一的字元,請檢查當前單詞是否與該字元對映到的單詞匹配。如果它們不匹配,則可以立即返回False,否則,請繼續掃描直到結束。
這種檢查對於以下情況將非常有效:
- “ abba”和“ dog cat cat dog”->返回True。
- “ abba”和“ dog cat cat fish”->返回False。
但這將失敗:
- “ abba”和“ dog dog dog dog”->返回True(預期False)。
一個解決方法是有兩個雜湊對映,一個用於將字元對映到單詞,另一個用於將單詞對映到字元。在掃描每個字元-單詞對時,
- 如果字元不在字元到單詞的對映中,則還要檢查該單詞是否也在單詞到字元的對映中。
如果該單詞已存在於單詞到字元的對映中,則您可以False立即返回,因為它之前已與其他字元對映過。
否則,更新兩個對映。 - 如果字元到單詞對映中的字元為IN,則只需要檢查當前單詞是否與字元到單詞對映中該字元對映到的單詞匹配。如果沒有,您可以False立即返回。
public boolean wordPatternWithTwoMap(String pattern, String s) {
// check edge
if (pattern == null || s == null) {
return pattern == s;
}
int len = pattern.length();
String[] sarray = s.split(" ");
if (len != sarray.length) {
return false;
}
Map<Character, String> pmap = new HashMap<>();
Map<String, Character> smap = new HashMap<>();
for (int i = 0; i < len; i++) {
char c = pattern.charAt(i);
String word = sarray[i];
if (!pmap.containsKey(c)) {
// smap contain, return false
if (smap.containsKey(word)) {
return false;
}
pmap.put(c, word);
smap.put(word, c);
} else {
String mapword = pmap.get(c);
if (!word.equals(mapword)) {
return false;
}
}
// build two map
pmap.put(c, word);
smap.put(word, c);
}
return true;
}
複雜度分析
時間複雜度: O(N)哪裡 ññ表示中的字數s或中的字元數pattern。
空間複雜度: O(M) 哪裡 中號中號代表中的唯一字數s。即使我們有兩個雜湊圖,字元到單詞雜湊圖的空間複雜度為O(1) 因為最多可以有26個鍵。
附錄:我們不能保留兩個雜湊對映,而只能保留字元到單詞的對映,並且只要我們發現不在對映中的字元,就可以檢查當前字元-單詞對中的單詞是否已經是當前值中的一個。字元到單詞的對映。但是,這是為了獲得更好的空間而付出的時間,因為檢查雜湊對映中的值是O(M) 操作地點 中號中號是雜湊圖中的鍵值對的數量。因此,如果我們決定採用這種方式,我們的時間複雜度將是O(NM)哪裡 ññ是中的唯一字元數pattern。
與方法1相似的另一種方法是使用雜湊集來跟蹤遇到的單詞。無需檢查單詞是否已存在於單詞到字元的對映中,只需檢查單詞是否在遇到的單詞雜湊集中。而且,您無需將單詞更新為字元對映,只需將單詞新增到遇到的單詞雜湊集即可。即使雜湊集和雜湊圖的big-O空間複雜度相同,雜湊集也將具有更好的實際空間複雜度。
方法2:單索引雜湊圖
直覺
而不是擁有兩個雜湊圖,我們可以有一個索引雜湊圖,它跟蹤中每個字元pattern和中每個單詞的首次出現s。遍歷每個字元-單詞對時,我們插入看不見的字元pattern和看不見的詞s。
目的是確保每個字元和單詞的索引匹配。一旦發現不匹配,我們可以返回False。
讓我們來看一些例子。
- pattern:‘abba’
- s:‘dog cat cat dog’
- ‘a’和’dog’-> map_index = {‘a’: 0, ‘dog’: 0}
索引“ a”和索引“ dog”相同。 - ‘b’和’cat’-> map_index = {‘a’: 0, ‘dog’: 0, ‘b’: 1, ‘cat’: 1}
索引“ b”和索引“ cat”相同。 - ‘b’和’cat’-> map_index = {‘a’: 0, ‘dog’: 0, ‘b’: 1, ‘cat’: 1}
“ b”已在對映中,無需更新。
“ cat”已經在對映中,無需更新。
索引“ b”和索引“ cat”相同。 - ‘a’和’dog’-> map_index = {‘a’: 0, ‘dog’: 0, ‘b’: 1, ‘cat’: 1}
“ a”已經在對映中,無需更新。
“ dog”已經在對映中,無需更新。
索引“ a”和索引“ dog”相同。
- pattern:‘abba’
- s:‘dog cat fish dog’
- ‘a’和’dog’-> map_index = {‘a’: 0, ‘dog’: 0}
索引“ a”和索引“ dog”相同。 - ‘b’和’cat’-> map_index = {‘a’: 0, ‘dog’: 0, ‘b’: 1, ‘cat’: 1}
索引“ b”和索引“ cat”相同。 - ‘b’和’fish’-> map_index = {‘a’: 0, ‘dog’: 0, ‘b’: 1, ‘cat’: 1, ‘fish’: 2}
“ b”已在對映中,無需更新。
“ b”的索引與“魚”的索引不同。返回False。
實作
區分字元和字串:在Python中沒有單獨的char型別。對於以下情況:
- pattern:‘abba’
- s:‘baab’
使用相同的雜湊圖將無法正常工作。一種解決方法是在每個字元前pattern新增“ char_”,在每個單詞前s新增“ word_”。
這裡需要注意:遍歷必須用Integer,而不是int. 因為Integer是物件,相同的int裝箱為不同的Integer。
public boolean wordPatternWithOneMap(String pattern, String s) {
// check edge
if (pattern == null || s == null) {
return pattern == s;
}
int len = pattern.length();
String[] sarray = s.split(" ");
if (len != sarray.length) {
return false;
}
Map<Object, Integer> map = new HashMap<>();
for (Integer i = 0; i < len; i++) {
char c = pattern.charAt(i);
String word = sarray[i];
if (!map.containsKey(c)) {
map.put(c, i);
}
if (!map.containsKey(word)) {
map.put(word, i);
}
if (map.get(c) != map.get(word)) {
return false;
}
}
return true;
}
複雜度分析
時間複雜度: 上)O(N) 哪裡 ññ代表中的字數s或中的字元數pattern。
空間複雜度: O(M)中號是中的唯一字元pattern和中的單詞的數量s。