|
| 1 | +/* |
| 2 | +https://www.geeksforgeeks.org/word-break-problem-dp-32/ |
| 3 | +https://leetcode.com/problems/word-break/discuss/43790/Java-implementation-using-DP-in-two-ways |
| 4 | +
|
| 5 | +NOTE - NOT SURE ABOUT THE TIME COMPLEXITY |
| 6 | +Comment from Leetcode - |
| 7 | +just want to add some comments for the time complexity: |
| 8 | +First DP: [length of s][size of dict][avg length of words in dict] |
| 9 | +Second DP: [length of s]^3 |
| 10 | +
|
| 11 | +BTW, for this kind of problem, which time complexity is [length of s][size of dict][avg length of words in dict]. We can usually remove [size of dict] by using Tire, remove [avg length of words in dict] by KMP, and what's more, remove both [size of dict] and [avg length of words in dict] by AC-automata. And of course these are all doable for this problem. |
| 12 | +This is just a insight for people who want to think deeper about this problem, hope it can help you :) |
| 13 | +
|
| 14 | +
|
| 15 | +QUESTION - |
| 16 | +Given an input string and a dictionary of words, find out if the input string can be segmented into a space-separated sequence of dictionary words. |
| 17 | +{ i, like, sam, sung, samsung, mobile, ice, cream, icecream, man, go, mango} |
| 18 | +Input: ilike |
| 19 | +Output: Yes |
| 20 | +The string can be segmented as "i like". |
| 21 | +
|
| 22 | +Input: ilikesamsung |
| 23 | +Output: Yes |
| 24 | +The string can be segmented as "i like samsung" |
| 25 | +or "i like sam sung". |
| 26 | +*/ |
| 27 | + |
| 28 | +//DP - Method 1 |
| 29 | + |
| 30 | +public boolean wordBreak(String s, Set<String> dict){ |
| 31 | + |
| 32 | + //T[i] indicates if it is possible to break the string s[0...i] into valid words from the dictionary |
| 33 | + boolean T[] = new boolean[s.length()+1]; |
| 34 | + |
| 35 | + //i=0 indicates empty string, which is valid ==> true |
| 36 | + T[0] = true; |
| 37 | + |
| 38 | + //the string under consideration starts from length=1 and goes up to length=s.length() |
| 39 | + //This is a bottom up approach - we start from the base condition ie. length=1 |
| 40 | + //During each iteration the string under consideration is s[0....i] |
| 41 | + for(int i=1 ; i <= s.length() ; i++){ |
| 42 | + |
| 43 | + //j is used to create a partition |
| 44 | + //The problem here is to check if s[0...i] can be broken down into valid words from the dictionary |
| 45 | + //We need to find where to make a break to get a valid result ==> explore all breaking points using 'j' |
| 46 | + //'j' breaks the string s[0...i] into two parts ==> s[0...j) and s[j...i) |
| 47 | + //subproblem is s[0...j) which has already been solved and the result is stored in T[j] |
| 48 | + //In this loop we basically - |
| 49 | + //1. choose a partition index - j |
| 50 | + //2. check if the suffix string is present in the dictionary |
| 51 | + //3. If it is then check if the prefix can be broken into valid words from the dictionary |
| 52 | + //4. If both 2 and 3 are true, we found another valid break of the string at index j, break as soon as 2 & 3 become true |
| 53 | + |
| 54 | + //we start at j=0 because we want to check if the entire word s[0...i] is present in the dictionary or not |
| 55 | + for(int j=0 ; j < i ; j++){ |
| 56 | + if(dict.contains(s.substring(j,i)) && T[j]){ |
| 57 | + T[i] = true; |
| 58 | + break; |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + return T[s.length()]; |
| 64 | +} |
| 65 | +//Time - O(n^2) OR O(n^3) ???? |
| 66 | + |
| 67 | +//DP-Method 2 |
| 68 | + |
| 69 | +public boolean wordBreak(String s, Set<String> dict){ |
| 70 | + |
| 71 | + //T[i] indicates if it is possible to break the string s[0...i] into valid words from the dictionary |
| 72 | + boolean T[] = new boolean[s.length()+1]; |
| 73 | + |
| 74 | + //i=0 indicates empty string, which is valid ==> true |
| 75 | + T[0] = true; |
| 76 | + |
| 77 | + //the string under consideration starts from length=1 and goes up to length=s.length() |
| 78 | + //This is a bottom up approach - we start from the base condition ie. length=1 |
| 79 | + //During each iteration the string under consideration is s[0....i] |
| 80 | + for(int i=1 ; i<=s.length() ; i++){ |
| 81 | + |
| 82 | + //look through all the strings in the dictionary and see if any of these words fits as a suffix in the current string |
| 83 | + for(String str : dict){ |
| 84 | + //1. To check if a string is present as a suffix we must first see if current 'i' ie. length of string under |
| 85 | + //consideration is greater than the string from the dictionary |
| 86 | + //2. If 1 is true we check if the string from dictionary matches with the suffix of string |
| 87 | + //3. If 2 is true we solve the subproblem s[0......(i-str.length())] to see if this part of the string can be broken |
| 88 | + |
| 89 | + /* |
| 90 | + This code is exactly the same as the above - the inner for loop is used for partitioning in both the code snippets. |
| 91 | + Here we use the dictionary string's length to partition |
| 92 | + In the previous code a separate index is used to partition |
| 93 | + */ |
| 94 | + |
| 95 | + if(i >= str.length() && s.substring(i-str.length(),i).equals(str) && T[i-str.length()]){ |
| 96 | + T[i] = true; |
| 97 | + break; |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | +} |
| 102 | +//Time - O(s.length()*dict.size()) |
0 commit comments