Leetcode 290. Word Pattern & 291. Word Pattern II

来源:互联网 发布:安卓4.4.4 java模拟器 编辑:程序博客网 时间:2024/06/05 10:32

290. Word Pattern

Total Accepted: 36588 Total Submissions: 124535 Difficulty: Easy

Given a pattern and a string str, find if str 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 str.

Examples:

  1. pattern = "abba", str = "dog cat cat dog" should return true.
  2. pattern = "abba", str = "dog cat cat fish" should return false.
  3. pattern = "aaaa", str = "dog cat cat dog" should return false.
  4. pattern = "abba", str = "dog dog dog dog" should return false.

Notes:
You may assume pattern contains only lowercase letters, and str contains lowercase letters separated by a single space.


思路:

一个hashmap搞定。取出pattern的char, 则对应位置str[i]:要么value存在且相同;要么不存在value。如果无key,也无value,则加入map中。如果无key但是存在value,返回false。

public class Solution {    public boolean wordPattern(String pattern, String str) {        if (pattern.isEmpty() || str.isEmpty()) {            return false;        }        String[] s = str.split(" ");        if (s.length != pattern.length()) {            return false;        }        HashMap<Character, String> hashMap = new HashMap<Character, String>();        for (int i = 0; i < pattern.length(); i++) {            if (hashMap.containsKey(pattern.charAt(i))) { // 有pattern的char, 则对应value必须相等                if (!hashMap.get(pattern.charAt(i)).equals(s[i])) {                    return false;                }            } else if (hashMap.containsValue(s[i])) { // 如果没该char的key, 但是却有str中对应位置的单词,说明该单词是由别的char加入                return false;            } else {                hashMap.put(pattern.charAt(i), s[i]);            }        }        return true;    }}


291. Word Pattern II

Given a pattern and a string str, find if str 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 substring in str.

Examples:

  1. pattern = "abab", str = "redblueredblue" should return true.
  2. pattern = "aaaa", str = "asdasdasdasd" should return true.
  3. pattern = "aabb", str = "xyzabcxzyabc" should return false.

Notes:
You may assume both pattern and str contains only lowercase letters.

思路:

UPDATE 9-25 之前没开会员,看得别人代码。现在开了做了一遍。写blog发现居然做过了,果然刷题将就的是过脑而不是单单的AC。完全没印象。

好久没debug这么久了。首先写了个dfs算法,用个hashmap保存已匹配的字符,然后如果无法匹配就backtracking。

逻辑大概是这样:dfs(pattern, 0, str, 0, map)

pattern的i位置去匹配str j位置。从m=j+1开始,取substring,然后去判断如下:

1. 如果map有这个key(chat at i in pattern),那么取出之后,当前j位置开始的字符串必须能匹配,否则return false回到上次循环;如果匹配了,那么j位置移动相应的位置,继续call dfs匹配。

2. 如果map里有value,那说明当前的substring被别的字符匹配了,需要跳过(continue)另取substring。

3. 到了这步,直接加入当前<char, substring>,然后继续call dfs。


思路很简单,结果 debug俩小时,卡在这个例子上:

"abab" 长度4
"redblueredblue" 长度14

返回了false。仔细检查逻辑写了如下log:

cur i j mr 0 0 1 无a这个key 放入(a, r) call 1e 1 1 2 无b这个key 放入(b, e) call 2d 2 2 3 有a这个key 和 get(a) = r 不相等 冲突直接return false call3, call2中删除( b, e)ed 1 1 3 无b这个key 放入(b, ed) call2。然后调用call 3.BUG ed没有放入b 2 3 4 有a这个key和get(a) = r不相等 call3返回false call2中删除(b, ed)edb 1 1 4 无b,放入(b, edb) call2 并调用call 3……edblue 1 1 7 放入(b, edblue) call 2中加入并调用call 3r 2 7 8 有a, get(a) == r call3发现match 修改m为e 3 8 9 有找到长度为6匹配

也就是说ed在上一次回溯之后没有放入。卡了好久,一步步分析逻辑和指针位置,最后灵机一动写了下面的代码(注释部分):

public class Solution {    public boolean wordPatternMatch(String pattern, String str) {        HashMap<Character, String> map = new HashMap<Character, String>();        if(dfs(pattern, 0, str, 0, map)) return true;        else return false;    }        boolean dfs(String p, int i, String str, int j, HashMap<Character, String> map){        if(i == p.length() && j == str.length()) return true;        if(i == p.length() || j == str.length()) return false;                int m = j + 1;        for(; m <= str.length(); m++){            String cur = str.substring(j, m);             // if(cur.equals("ed")){            //     System.out.println(cur + " " + i + " "+ j + " "+m);            //     System.out.println(map.containsKey(p.charAt(i)));            //     System.out.println(map.containsValue(cur));            // }            if(map.containsKey(p.charAt(i))){                String match = map.get(p.charAt(i));                if(canFindMatch(str, match, j)){                    m = j + match.length();                    if(dfs(p, i + 1, str, m, map)) return true;                }                return false; // 当前key无法匹配 或者 当前key匹配之后后面仍无法匹配            }else if(map.containsValue(cur)){                continue;            }else{                map.put(p.charAt(i), cur);                if(dfs(p, i + 1, str, m, map)) return true;                map.remove(cur);            }        }        return false;    }        boolean canFindMatch(String s, String match, int i){        for(int j = 0; j < match.length(); j++){            if(s.charAt(i + j) != match.charAt(j)) return false;        }        return true;    }}

发现卧槽,System.out.println(map.containsKey(p.charAt(i))) 居然为true。然后一看sb了,map remove(key)而不是 map remove(value).... 还好不是面试,这什么错误。。


还有个bug是canFindMatch应该提前判断i + j是否超过length,要不会OutOfBound,有可能在末尾匹配一个很长的字符串,所以要么先判断长度+位置是否超标再call,要么直接call里面设置一个判断。

最终版:

public class Solution {    public boolean wordPatternMatch(String pattern, String str) {        HashMap<Character, String> map = new HashMap<Character, String>();        if(dfs(pattern, 0, str, 0, map)) return true;        else return false;    }        boolean dfs(String p, int i, String str, int j, HashMap<Character, String> map){        if(i == p.length() && j == str.length()) return true;        if(i == p.length() || j == str.length()) return false;                for(int m = j + 1; m <= str.length(); m++){            String cur = str.substring(j, m);             if(map.containsKey(p.charAt(i))){                String match = map.get(p.charAt(i));                if(canFindMatch(str, match, j)){                    m = j + match.length();                    if(dfs(p, i + 1, str, m, map)) return true;                }                return false; // 当前key无法匹配 或者 当前key匹配之后后面仍无法匹配            }else if(map.containsValue(cur)){                continue;            }else{                map.put(p.charAt(i), cur);                if(dfs(p, i + 1, str, m, map)) return true;                map.remove(p.charAt(i));            }        }        return false;    }        boolean canFindMatch(String s, String match, int i){        for(int j = 0; j < match.length(); j++){            if(i + j >= s.length()) return false;            if(s.charAt(i + j) != match.charAt(j)) return false;        }        return true;    }}



==================== 之前写的分界线 =============================== 

programcreek上有很好的思路,discuss里也有很好的思路。

首先就是需要记录匹配的对应位置,比如pattern 1位置对应str的4。这个题肯定是要试所有的str substring组合可能性,所以必然是backtracking。

backtracking就一定是递归,参数是pattern, index位置1, str, index位置2。然后接下来可以传递一个参数或者俩参数。一个map保存<Char, String>,一个set保存String。

如参考文章中所说:


如果是一个参数:

首先对应index1, char c = pattern.charAt(i); 然后有两种情况。如果map中不含这个字符,说明该字符没有出现过,!!!并且在取str的substring时需要保证取到的substring没有出现过!!!!(比如ab, cc, a对应了c, 那么在match b的时候,右边是不能取到c的,因为这个c已经跟左边的a对应,然而b没出现过就是因为b!=a,所以b不能和现在这个c对应)。因此判断条件应为:

!map.containsKey(c) && !map.containsValue(sub);

如果是出现过那么当前取到的substring必须和保存的substring值相等:

map.containsKey(c) && map.get(c).equals(sub)


每次取一个字符去判断是否与c对应的string相等时:Since containsValue() method is used here, the time complexity is O(n). 于是提出了两参数,每次还要将匹配的substring放入 set,纯粹为了加快速度。

当无法匹配时,去除对应容器中的元素并返回false。

public boolean wordPatternMatch(String pattern, String str) {    if(pattern.length()==0 && str.length()==0)        return true;    if(pattern.length()==0)        return false;     HashMap<Character, String> map = new HashMap<Character, String>();     return helper(pattern, str, 0, 0, map);} public boolean helper(String pattern, String str, int i, int j, HashMap<Character, String> map){    if(i==pattern.length() && j==str.length()){        return true;    }     if(i>=pattern.length() || j>=str.length())        return false;     char c = pattern.charAt(i);    for(int k=j+1; k<=str.length(); k++){        String sub = str.substring(j, k);        if(!map.containsKey(c) && !map.containsValue(sub)){            map.put(c, sub);            if(helper(pattern, str, i+1, k, map))                return true;            map.remove(c);        }else if(map.containsKey(c) && map.get(c).equals(sub)){            if(helper(pattern, str, i+1, k, map))                return true;        }    }     return false;}

public boolean wordPatternMatch(String pattern, String str) {    if(pattern.length()==0 && str.length()==0)        return true;    if(pattern.length()==0)        return false;     HashMap<Character, String> map = new HashMap<Character, String>();    HashSet<String> set = new HashSet<String>();    return helper(pattern, str, 0, 0, map, set);} public boolean helper(String pattern, String str, int i, int j, HashMap<Character, String> map, HashSet<String> set){    if(i==pattern.length() && j==str.length()){        return true;    }     if(i>=pattern.length() || j>=str.length())        return false;     char c = pattern.charAt(i);    for(int k=j+1; k<=str.length(); k++){        String sub = str.substring(j, k);        if(!map.containsKey(c) && !set.contains(sub)){            map.put(c, sub);            set.add(sub);            if(helper(pattern, str, i+1, k, map, set))                return true;            map.remove(c);            set.remove(sub);        }else if(map.containsKey(c) && map.get(c).equals(sub)){            if(helper(pattern, str, i+1, k, map, set))                return true;        }    }     return false;}



0 0
原创粉丝点击