LeetCode 291 - Word Pattern II


leetcode 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.
The problem becomes much more difficult after the spaces are removed. Now we need to determine which part matchs which part by ourselves.
https://discuss.leetcode.com/topic/26750/share-my-java-backtracking-solution
We can solve this problem using backtracking, we just have to keep trying to use a character in the pattern to match different length of substrings in the input string, keep trying till we go through the input string and the pattern.
For example, input string is "redblueredblue", and the pattern is "abab", first let's use 'a' to match "r"'b' to match "e", then we find that 'a' does not match "d", so we do backtracking, use 'b' to match "ed", so on and so forth ...
When we do the recursion, if the pattern character exists in the hash map already, we just have to see if we can use it to match the same length of the string. For example, let's say we have the following map:
'a': "red"
'b': "blue"
now when we see 'a' again, we know that it should match "red", the length is 3, then let's see if str[i ... i+3] matches 'a', where i is the current index of the input string. Thanks to StefanPochmann's suggestion, in Java we can elegantly use str.startsWith(s, i) to do the check.
Also thanks to i-tikhonov's suggestion, we can use a hash set to avoid duplicate matches, if character a matches string "red", then character b cannot be used to match "red". In my opinion though, we can say apple (pattern 'a') is "fruit", orange (pattern 'o') is "fruit", so they can match the same string, anyhow, I guess it really depends on how the problem states.
The following code should pass OJ now, if we don't need to worry about the duplicate matches, just remove the code that associates with the hash set.
  public boolean wordPatternMatch(String pattern, String str) {
    Map<Character, String> map = new HashMap<>();
    Set<String> set = new HashSet<>();
    
    return isMatch(str, 0, pattern, 0, map, set);
  }
  
  boolean isMatch(String str, int i, String pat, int j, Map<Character, String> map, Set<String> set) {
    // base case
    if (i == str.length() && j == pat.length()) return true;
    if (i == str.length() || j == pat.length()) return false;
    
    // get current pattern character
    char c = pat.charAt(j);
    
    // if the pattern character exists
    if (map.containsKey(c)) {
      String s = map.get(c);
      
      // then check if we can use it to match str[i...i+s.length()]
      if (!str.startsWith(s, i)) {
        return false;
      }
      
      // if it can match, great, continue to match the rest
      return isMatch(str, i + s.length(), pat, j + 1, map, set);
    }
    
    // pattern character does not exist in the map
    for (int k = i; k < str.length(); k++) {
      String p = str.substring(i, k + 1);

      if (set.contains(p)) {
        continue;
      }

      // create or update it
      map.put(c, p);
      set.add(p);
      
      // continue to match the rest
      if (isMatch(str, k + 1, pat, j + 1, map, set)) {
        return true;
      }

      // backtracking
      map.remove(c);
      set.remove(p);
    }
    
    // we've tried our best but still no luck
    return false;
  }

http://buttercola.blogspot.com/2015/10/leetcode-word-pattern-ii.html
https://kennyzhuang.gitbooks.io/leetcode-lock/content/291_word_pattern_ii.html
    public boolean wordPatternMatch(String pattern, String str) {
        if ((pattern == null || pattern.length() == 0) && (str == null || str.length() == 0)) {
            return true;
        }
         
        if ((pattern == null || pattern.length() == 0) || (str == null || str.length() == 0)) {
            return false;
        }
         
        Map<Character, String> forwardMap = new HashMap<>();
        Map<String, Character> invertedMap = new HashMap<>();
         
        return wordPatternMatchHelper(0, pattern, 0, str, forwardMap, invertedMap);
    }
     
    private boolean wordPatternMatchHelper(int pStart, String pattern,
                                      int sStart, String str,
                                      Map<Character, String> forwardMap,
                                      Map<String, Character> invertedMap) {
        if (pStart == pattern.length() && sStart == str.length()) {
            return true;
        }
         
        if (pStart >= pattern.length() || sStart >= str.length()) {
            return false;
        }
         
        char pChar = pattern.charAt(pStart);
        for (int i = sStart; i < str.length(); i++) {
            String curr = str.substring(sStart, i + 1);
             
            if ((!forwardMap.containsKey(pChar)) && (!invertedMap.containsKey(curr))) {
                forwardMap.put(pChar, curr);
                invertedMap.put(curr, pChar);
                 
                if (wordPatternMatchHelper(pStart + 1, pattern, i + 1,
                        str, forwardMap, invertedMap)) {
                    return true;
                }
                 
                forwardMap.remove(pChar);
                invertedMap.remove(curr);
            } else if (forwardMap.containsKey(pChar) && invertedMap.containsKey(curr)) {
                String dict = forwardMap.get(pChar);
                char pCharDict = invertedMap.get(curr);
                 
                // IMPORTANT !! If not equal, instead of returnning false immedidately,
                // We need to try other longer substrings.
// case ab redred a(red) b also map to red
// case aa abac
                if (!dict.equals(curr) || pCharDict != pChar) {
                    continue;
                }
                 
                if (wordPatternMatchHelper(pStart + 1, pattern, i + 1, str,
                        forwardMap, invertedMap)) {
                    return true;
                }
            }
        }
         
        return false;
    }
https://discuss.leetcode.com/topic/26819/20-lines-java-clean-solution-easy-to-understand
Map<Character,String> map =new HashMap();
Set<String> set =new HashSet();
public boolean wordPatternMatch(String pattern, String str) {
    if(pattern.isEmpty()) return str.isEmpty();
    if(map.containsKey(pattern.charAt(0))){
        String value= map.get(pattern.charAt(0));
        if(str.length()<value.length() || !str.substring(0,value.length()).equals(value)) return false;
        if(wordPatternMatch(pattern.substring(1),str.substring(value.length()))) return true;
    }else{
        for(int i=1;i<=str.length();i++){
            if(set.contains(str.substring(0,i))) continue;
            map.put(pattern.charAt(0),str.substring(0,i));
            set.add(str.substring(0,i));
            if(wordPatternMatch(pattern.substring(1),str.substring(i))) return true;
            set.remove(str.substring(0,i));
            map.remove(pattern.charAt(0));
        }
    }
    return false;
}
http://www.programcreek.com/2014/07/leetcode-word-pattern-ii-java/
The time complexity then is f(n) = n*(n-1)*... *1=n^n.
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;
}
https://segmentfault.com/a/1190000003827151
    Map<Character, String> map;
    Set<String> set;
    boolean res;
    
    public boolean wordPatternMatch(String pattern, String str) {
        // 和I中一样,Map用来记录字符和字符串的映射关系
        map = new HashMap<Character, String>();
        // Set用来记录哪些字符串被映射了,防止多对一映射
        set = new HashSet<String>();
        res = false;
        // 递归回溯
        helper(pattern, str, 0, 0);
        return res;
    }
    
    public void helper(String pattern, String str, int i, int j){
        // 如果pattern匹配完了而且str也正好匹配完了,说明有解
        if(i == pattern.length() && j == str.length()){
            res = true;
            return;
        }
        // 如果某个匹配超界了,则结束递归
        if(i >= pattern.length() || j >= str.length()){
            return;
        }
        char c = pattern.charAt(i);
        // 尝试从当前位置到结尾的所有划分方式
        for(int cut = j + 1; cut <= str.length(); cut++){
            // 拆出一个子串
            String substr = str.substring(j, cut);
            // 如果这个子串没有被映射过,而且当前pattern的字符也没有产生过映射
            // 则新建一对映射,并且继续递归求解
            if(!set.contains(substr) && !map.containsKey(c)){
                map.put(c, substr);
                set.add(substr);
                helper(pattern, str, i + 1, cut);
                map.remove(c);
                set.remove(substr);
            // 如果已经有映射了,但是是匹配的,也继续求解
            } else if(map.containsKey(c) && map.get(c).equals(substr)){
                helper(pattern, str, i + 1, cut);
            }
            // 否则跳过该子串,尝试下一种拆分
        }
    }
https://leetcode.com/discuss/63252/share-my-java-backtracking-solution
can we check map.containsValue(p) instead of using another hashset?
sure, it is possible to use containsValue() method. But it is slower, since the method's complexity is O(n).


Not exactly cost O(n) more, since there are only 26 keys at most for this particular problem, it may cost slightly more time. It saves some space in SET on the other hand.
// Use Guava BidiMap,  AbstractDualBidiMap

public boolean wordPatternMatch(String pattern, String str) { Map<Character, String> map = new HashMap<>(); Set<String> set = new HashSet<>(); return isMatch(str, 0, pattern, 0, map, set); } boolean isMatch(String str, int i, String pat, int j, Map<Character, String> map, Set<String> set) { // base case if (i == str.length() && j == pat.length()) return true; if (i == str.length() || j == pat.length()) return false; // get current pattern character char c = pat.charAt(j); // if the pattern character exists if (map.containsKey(c)) { String s = map.get(c); // then check if we can use it to match str[i...i+s.length()] if (!str.startsWith(s, i)) { return false; } // if it can match, great, continue to match the rest return isMatch(str, i + s.length(), pat, j + 1, map, set); } // pattern character does not exist in the map for (int k = i; k < str.length(); k++) { String p = str.substring(i, k + 1); if (set.contains(p)) { continue; } // create or update it map.put(c, p); set.add(p); // continue to match the rest if (isMatch(str, k + 1, pat, j + 1, map, set)) { return true; } // backtracking map.remove(c); set.remove(p); } // we've tried our best but still no luck return false; }
http://www.meetqun.com/thread-11391-1-1.html
public class Solution {4 `+ U& C4 n  ?3 u9 R8 [
    public boolean wordPatternMatch(String pattern, String str) {) @* K/ S; O- {! |3 R4 ?- k
        HashMap<Character, String> mapPtoS = new HashMap<Character, String>();
        HashMap<String, Character> mapStoP = new HashMap<String, Character>();
        9 _9 i0 r$ A/ @' @+ b, ?  t
        return dfs(pattern, str, 0,0, mapPtoS, mapStoP);
    }; p! u3 b; T' d% m* l& [
    private boolean dfs(String pattern, String str, int idxPat, int idxStr, HashMap<Character, String> mapPtoS, HashMap<String, Character> mapStoP){& E: h+ C; F5 _7 ^% J1 C) ~+ g2 m
        int patLength = pattern.length();( A4 G3 G8 W4 y
        int strLength = str.length();
        if(idxPat==patLength&&idxStr==strLength) return true;* W, L# s  s) U% E. m! x3 ~
        if(idxPat==patLength||idxStr==strLength) return false;
        4 S# x) p2 o# d$ a3 j
        char p = pattern.charAt(idxPat);# ^+ E$ ^2 @# p- ]6 r  r4 N0 p
        for(int i=idxStr+1;i<=strLength;i++){
            String item = str.substring(idxStr, i);
            + k3 q. W1 y. y7 u
            boolean findP = true;
            if(mapPtoS.containsKey(p) && !mapPtoS.get(p).equals(item)) continue;
            else if(!mapPtoS.containsKey(p)){$ `1 j; n! f3 S# C
                mapPtoS.put(p, item);6 B8 p0 m9 ?' T6 n5 R" G2 l
                findP = false;
            }8 x, J% n* K. [& x
            
            boolean findStr = true;
            if(mapStoP.containsKey(item) && mapStoP.get(item)!=p) {
                if(!findP) mapPtoS.remove(p);6 O, x: r1 @; |1 M
                continue; 
            }) Y! N! y( G3 \4 }) Y6 Z
            else if(!mapStoP.containsKey(item)){
                mapStoP.put(item, p);
                findStr = false;
            }- R  ]; _- h6 S8 U# `7 Z$ ^& E$ t/ E
            
            if(dfs(pattern, str, idxPat+1, i, mapPtoS, mapStoP)) return true;0 O' b7 R6 a& o1 s: |
            else{
                if(!findP) mapPtoS.remove(p);
                if(!findStr) mapStoP.remove(item);* J* H. `, J4 ]3 s) B
            }
        }9 @3 o+ C7 ?+ V/ V3 v( X
        ! H% J6 K6 E* k: e' ?3 B
        return false;
    }9 y& A0 w2 y9 i5 f3 F) H" M
}
. |; m: d+ j- S0 v. M
==============$ }$ _& d. f: {8 G. _0 m
A typical backtracking. I use two hashmap to guarantee one pattern only map to exact one string. Note we need to remove new added element in hashmap if current splitted string is illegal
20 lines JAVA clean solution, easy to understand
http://dartmooryao.blogspot.com/2016/05/leetcode-291-word-pattern-ii.html
public class Solution { Map<Character,String> map =new HashMap(); Set<String> set =new HashSet(); public boolean wordPatternMatch(String pattern, String str) { if(pattern.isEmpty()) return str.isEmpty(); if(map.containsKey(pattern.charAt(0))){ String value= map.get(pattern.charAt(0)); if(str.length()<value.length() || !str.substring(0,value.length()).equals(value)) return false; if(wordPatternMatch(pattern.substring(1),str.substring(value.length()))) return true; }else{ for(int i=1;i<=str.length();i++){ if(set.contains(str.substring(0,i))) continue; map.put(pattern.charAt(0),str.substring(0,i)); set.add(str.substring(0,i)); if(wordPatternMatch(pattern.substring(1),str.substring(i))) return true; set.remove(str.substring(0,i)); map.remove(pattern.charAt(0)); } } return false; }
http://shibaili.blogspot.com/2015/10/day-132-287-find-duplicate-number.html
back tracking
对一个pattern[i], 试遍每一种可能
    bool helper(string pattern, int i, string str, int is, unordered_map<char,string> &ptos, unordered_map<string,char> &stop) {
        if (i == pattern.length() && is == str.length()) return true;
        if (i == pattern.length() || is == str.length()) return false;
         
        if (ptos.find(pattern[i]) != ptos.end()) {
            if (ptos[pattern[i]] == str.substr(is,ptos[pattern[i]].length())) {
                return helper(pattern,i + 1, str, is + ptos[pattern[i]].length(),ptos,stop);
            }
            return false;
        }
         
        for (int j = is; j < str.length(); j++) {
            string word = str.substr(is,j - is + 1);
            if (stop.find(word) != stop.end()) continue;
             
            ptos[pattern[i]] = word;
            stop[word] = pattern[i];
            if (helper(pattern, i + 1, str, j + 1, ptos,stop)) return true;
            ptos.erase(pattern[i]);
            stop.erase(word);
        }
         
        return false;
    }
    bool wordPatternMatch(string pattern, string str) {
        unordered_map<char,string> ptos;
        unordered_map<string,char> stop;
         
        return helper(pattern,0,str,0,ptos,stop);
    }

Pattern Matching: You are given two strings, pattern and value. The pattern string consists of
just the letters a and b, describing a pattern within a string. For example, the string catcatgocatgo
matches the pattern aabab (where cat is a and go is b). It also matches patterns like a, ab, and b.

Write a method to determine if value matches pattern

boolean doesMatch(String pattern, String value) {
        if (pattern.length()== 0) return value.length() == 0;

       int size = value.length();
        for (int mainSize = 0; mainSize < size; mainSize++) {
                String main= value.substring(0, mainSize);
                for (int altStart = mainSize; altStart <= size; ,altStart++) {
                        for (int altEnd = altStart; altEnd <= size; altEnd++) {
                                String alt= value.substring(altStart, altEnd);
                                String cand = buildFromPattern(pattern, main, alt);
                                if (cand.equals(value)) {
                                        return true;
                                }
                        }
                }
        }
        return false;
}

String buildFromPattern(String pattern, String main, String alt) {
        StringBuffer sb = new StringBuffer();
        char first= pattern.charAt(0);
        for (char c : pattern.toCharArray()) {
                if (c == first) {
                        sb.append(main);
                } else {
                        sb.append(alt);
                }
        }
        return sb.toString();
}

https://discuss.leetcode.com/topic/26750/share-my-java-backtracking-solution

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts