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