@@ -26,6 +26,12 @@ sequences of words (sentences). The order in which the sentences are listed is n
2626
2727## Solutions
2828
29+ 1 . [ Naive Approach] ( #naive-approach )
30+ 2 . [ Backtracking] ( #backtracking )
31+ 3 . [ Dynamic Programming - tabulation] ( #optimized-approach-using-dynamic-programming---tabulation )
32+ 4 . [ Dynamic Programming - memoization] ( #dynamic-programming---memoization )
33+ 5 . [ Trie Optimization] ( #trie-optimization )
34+
2935### Naive Approach
3036
3137The naive approach to solve this problem is to use a traditional recursive strategy in which we take each prefix of the
@@ -58,6 +64,68 @@ of the string, and `m` is the length of the longest word in the dictionary.
5864
5965The space complexity is O(k^n * n), where k is the number of words in the dictionary and ` n ` is the length of the string.
6066
67+ ### Backtracking
68+
69+ Initially, we might think of a brute-force approach where we systematically explore all possible ways to break the
70+ string into words from the dictionary. This leads us to the backtracking strategy, where we recursively try to form
71+ words from the string and add them to a current sentence if they are in the dictionary. If the current prefix doesn't
72+ lead to a valid solution, we backtrack by removing the last added word and trying the next possible word. This ensures
73+ we explore all possible segmentations of the string.
74+
75+ At each step, we consider all possible end indices for substrings starting from the current index. For each substring,
76+ we check if it exists in the dictionary. If the substring is a valid word, we append it to the current sentence and
77+ recursively call the function with the updated index, which is the end index of the substring plus one.
78+
79+ If we reach the end of the string, it means we have found a valid segmentation, and we can add the current sentence to
80+ the results. However, if we encounter a substring that is not a valid word, we backtrack by returning from that
81+ recursive call and trying the next possible end index.
82+
83+ The backtracking approach will be inefficient due to the large number of recursive calls, especially for longer strings.
84+ To increase efficiency, we will convert the word dictionary into a set for constant-time lookups. However, the overall
85+ time complexity remains high because we explore all possible partitions.
86+
87+ The process is visualized below:
88+
89+ ![ Backtracking Solution] ( ./images/solution/word_break_backtracking_solution_1.png )
90+
91+ #### Algorithm
92+
93+ - Convert the ` word_dict ` array into an unordered set ` word_set ` for efficient lookups.
94+ - Initialize an empty array ` results ` to store valid sentences.
95+ - Initialize an empty string currentSentence to keep track of the sentence being constructed.
96+ - Call the ` backtrack ` function with the input string ` s ` , ` word_set ` , ` current_sentence ` , ` results ` , and a starting
97+ index set to 0, the beginning of the input string.
98+ - Base case: If the ` start_index ` is equal to the length of the string, add the ` current_sentence ` to ` results ` and
99+ return as it means that ` current_sentence ` represents a valid sentence.
100+ - Iterate over possible ` end_index ` values from ` start_index ` + 1 to the end of the string.
101+ - Extract the substring word from startIndex to ` end_index - 1 ` .
102+ - If word is found in ` word_set ` :
103+ - Store the current currentSentence in ` original_sentence ` .
104+ - Append word to ` current_sentence ` (with a space if needed).
105+ - Recursively call ` backtrack ` with the updated ` current_sentence ` and ` end_index ` .
106+ - Reset ` current_sentence ` to its original value (` original_sentence ` ) to backtrack and try the next ` end_index ` .
107+ - Return from the backtrack function.
108+ - Return results.
109+
110+ #### Complexity Analysis
111+
112+ Let n be the length of the input string.
113+
114+ ##### Time complexity: O(n⋅2^n)
115+
116+ The algorithm explores all possible ways to break the string into words. In the worst case, where each character can be
117+ treated as a word, the recursion tree has 2^n leaf nodes, resulting in an exponential time complexity. For each leaf
118+ node, O(n) work is performed, so the overall complexity is O(n⋅2^n).
119+
120+ ##### Space complexity: O(2^n)
121+
122+ The recursion stack can grow up to a depth of n, where each recursive call consumes additional space for storing the
123+ current state.
124+
125+ Since each position in the string can be a split point or not, and for n positions, there are 2^n possible combinations
126+ of splits. Thus, in the worst case, each combination generates a different sentence that needs to be stored, leading to
127+ exponential space complexity.
128+
61129### Optimized approach using dynamic programming - tabulation
62130
63131Since the recursive solution to this problem is very costly, let’s see if we can reduce this cost in any way. Dynamic
@@ -162,3 +230,7 @@ combinations
162230
163231The space complexity is O(n * v), where n is the length of the string and v is the number of valid combinations stored in
164232the ` dp ` array.
233+
234+ ### Dynamic Programming - Memoization
235+
236+ ### Trie Optimization
0 commit comments