Skip to content

Commit ea6a41e

Browse files
committed
Word Break Problem in python.
1 parent 81889df commit ea6a41e

1 file changed

Lines changed: 145 additions & 13 deletions

File tree

python/dynamic/breakword.py

Lines changed: 145 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,152 @@
1-
# break single word with no spaces with multiple words into spaces
2-
# https://github.com/mission-peace/interview/blob/master/src/com/interview/dynamic/BreakMultipleWordsWithNoSpaceIntoSpace.java
1+
"""
2+
Problem Statement
3+
=================
4+
Given a string and a dictionary, split the string in to multiple words so that each word belongs to the dictionary.
35
4-
def break_word(input, dicts):
5-
if len(input) == 0:
6+
Video
7+
-----
8+
* https://youtu.be/WepWFGxiwRs
9+
10+
11+
Analysis
12+
--------
13+
14+
* word_break_recursive: Exponential
15+
* word_break_dp : O(n^3)
16+
17+
Solution
18+
--------
19+
20+
if input[i..j] belongs in a dictionary:
21+
DP[i][j] = True
22+
else:
23+
DP[i][j] = True if DP[i][k-1] and DP[k][j] for any k between i to j.
24+
25+
Multiple different implementations are given below.
26+
"""
27+
28+
29+
def word_break_recursive(given_string, dictionary):
30+
""""Returns None if the given string cannot be broken into words, otherwise returns space separate words."""
31+
32+
given_string_length = len(given_string)
33+
if given_string_length == 0:
634
return ""
735
string = ""
8-
for i in range(len(input)):
9-
string += input[i]
10-
if string in dicts:
11-
r = break_word(input[i+1:], dicts)
36+
for i in range(given_string_length):
37+
string += given_string[i]
38+
if string in dictionary:
39+
r = word_break_recursive(given_string[i + 1:], dictionary)
1240
if r is not None:
1341
string += " " + r
1442
return string
15-
return None;
43+
return None
44+
45+
46+
def word_break_dp(given_string, dictionary):
47+
"""Returns None if the given string cannot be broken into words, otherwise returns space separated words."""
48+
49+
given_string_length = len(given_string)
50+
51+
# -1 indicates the word cannot be split.
52+
DP = [[-1 for _ in range(given_string_length)] for _ in range(given_string_length)]
53+
54+
for substring_length in range(1, given_string_length + 1):
55+
for start in range(0, given_string_length - substring_length + 1):
56+
end = start + substring_length - 1
57+
substring = given_string[start: end + 1]
58+
if substring in dictionary:
59+
DP[start][end] = start
60+
continue
61+
62+
for split in range(start + 1, end + 1):
63+
if DP[start][split - 1] != -1 and DP[split][end] != -1:
64+
DP[start][end] = split
65+
break
66+
67+
if DP[0][-1] == -1:
68+
return None
69+
70+
words = []
71+
start_index = 0
72+
end_index = given_string_length - 1
73+
while start_index < given_string_length:
74+
split_index = DP[start_index][end_index]
75+
if start_index == split_index:
76+
words.append(given_string[start_index: end_index + 1])
77+
break
78+
else:
79+
words.append(given_string[start_index: split_index])
80+
start_index = split_index
81+
82+
return " ".join(words)
83+
84+
85+
def is_word_break_possible(given_string, dictionary):
86+
"""Returns if any word break is possible amongst the multiple word breaks in the sentence."""
87+
88+
DP = dict()
89+
max_word_length = len(max(dictionary, key=len))
90+
return is_word_break_possible_recursive_helper(given_string, dictionary, 0, max_word_length, DP)
91+
92+
93+
def is_word_break_possible_recursive_helper(given_string, dictionary, start, max_word_length, DP):
94+
if start == len(given_string):
95+
return True
96+
97+
if start in DP:
98+
return DP[start]
99+
100+
for i in range(start, start + max_word_length):
101+
if i < len(given_string):
102+
new_word = given_string[start: i + 1]
103+
if new_word in dictionary:
104+
continue
105+
if is_word_break_possible_recursive_helper(given_string, dictionary, i + 1, max_word_length, DP):
106+
DP[start] = True
107+
return True
108+
109+
DP[start] = False
110+
return False
111+
112+
113+
def all_possible_word_break_helper(given_string, dictionary, start, max_word_length, DP):
114+
""""Returns all possible word breaks in a given sentence."""
115+
if start == len(given_string):
116+
return [""]
117+
118+
if start in DP:
119+
return DP[start]
120+
121+
words = []
122+
for i in range(start, start + max_word_length):
123+
if i < len(given_string):
124+
new_word = given_string[start: i + 1]
125+
if new_word not in dictionary:
126+
continue
127+
sub_words = all_possible_word_break_helper(given_string, dictionary, i + 1, max_word_length, DP)
128+
for word in sub_words:
129+
extra_space = "" if len(word) == 0 else " "
130+
words.append(new_word + extra_space + word)
131+
132+
DP[start] = words
133+
return words
134+
135+
136+
def all_possible_word_breaks(given_string, dictionary):
137+
DP = dict()
138+
max_word_length = len(max(dictionary, key=len))
139+
return all_possible_word_break_helper(given_string, dictionary, 0, max_word_length, DP)
140+
141+
142+
if __name__ == '__main__':
143+
dictionary = {"joy", "likes", "to", "play"}
144+
given_string = "joylikestoplay"
145+
146+
assert True == is_word_break_possible(given_string, dictionary)
147+
assert "joy likes to play " == word_break_recursive(given_string, dictionary)
148+
assert "joy likes to play" == word_break_dp(given_string, dictionary)
16149

17-
dicts = ["play", "to", "had", "I", "like"]
18-
input = "Ihadliketoplay"
19-
result = break_word(input, dicts)
20-
print(result)
150+
dictionary = {"pea", "nut", "peanut", "butter"}
151+
given_string = "peanutbutter"
152+
assert ['pea nut butter', 'peanut butter'] == all_possible_word_breaks(given_string, dictionary)

0 commit comments

Comments
 (0)