Skip to content

Commit 34a6faf

Browse files
axayjhaPanquesito7github-actionskvedala
authored
adding word break DP approach (#1278)
* adding word break DP approach * fixing formatting * fixing linting issues * adding documentation and other enhancements * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * updating DIRECTORY.md * clang-format and clang-tidy fixes for 061c21a * docs: fixed documentation * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * Update dynamic_programming/word_break.cpp Co-authored-by: David Leal <[email protected]> * clang-format and clang-tidy fixes for d8ab6b0 * Update dynamic_programming/word_break.cpp Co-authored-by: Krishna Vedala <[email protected]> * clang-format and clang-tidy fixes for 05d7ca1 Co-authored-by: David Leal <[email protected]> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Krishna Vedala <[email protected]>
1 parent a55e362 commit 34a6faf

File tree

2 files changed

+187
-0
lines changed

2 files changed

+187
-0
lines changed

DIRECTORY.md

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
* [Searching Of Element In Dynamic Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/searching_of_element_in_dynamic_array.cpp)
7070
* [Shortest Common Supersequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/shortest_common_supersequence.cpp)
7171
* [Tree Height](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/tree_height.cpp)
72+
* [Word Break](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/word_break.cpp)
7273

7374
## Geometry
7475
* [Jarvis Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/geometry/jarvis_algorithm.cpp)

dynamic_programming/word_break.cpp

+186
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/**
2+
* @file
3+
* @brief [Word Break Problem](https://leetcode.com/problems/word-break/)
4+
* @details
5+
* Given a non-empty string s and a dictionary wordDict containing a list of
6+
* non-empty words, determine if s can be segmented into a space-separated
7+
* sequence of one or more dictionary words.
8+
*
9+
* Note:
10+
* The same word in the dictionary may be reused multiple times in the
11+
* segmentation. You may assume the dictionary does not contain duplicate words.
12+
*
13+
* Example 1:
14+
* Input: s = "leetcode", wordDict = ["leet", "code"]
15+
* Output: true
16+
* Explanation: Return true because "leetcode" can be segmented as "leet code".
17+
*
18+
* Example 2:
19+
* Input: s = "applepenapple", wordDict = ["apple", "pen"]
20+
* Output: true
21+
* Explanation: Return true because "applepenapple" can be segmented as "apple
22+
* pen apple". Note that you are allowed to reuse a dictionary word.
23+
*
24+
* Example 3:
25+
* Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
26+
* Output: false
27+
*
28+
* @author [Akshay Anand] (https://github.com/axayjha)
29+
*/
30+
31+
#include <cassert>
32+
#include <climits>
33+
#include <iostream>
34+
#include <string>
35+
#include <unordered_set>
36+
#include <vector>
37+
38+
/**
39+
* @namespace dynamic_programming
40+
* @brief Dynamic programming algorithms
41+
*/
42+
namespace dynamic_programming {
43+
44+
/**
45+
* @namespace word_break
46+
* @brief Functions for [Word Break](https://leetcode.com/problems/word-break/)
47+
* problem
48+
*/
49+
namespace word_break {
50+
51+
/**
52+
* @brief Function that checks if the string passed in param is present in
53+
* the the unordered_set passed
54+
*
55+
* @param str the string to be searched
56+
* @param strSet unordered set of string, that is to be looked into
57+
* @returns `true` if str is present in strSet
58+
* @returns `false` if str is not present in strSet
59+
*/
60+
bool exists(const std::string &str,
61+
const std::unordered_set<std::string> &strSet) {
62+
return strSet.find(str) != strSet.end();
63+
}
64+
65+
/**
66+
* @brief Function that checks if the string passed in param can be
67+
* segmented from position 'pos', and then correctly go on to segment the
68+
* rest of the string correctly as well to reach a solution
69+
*
70+
* @param s the complete string to be segmented
71+
* @param strSet unordered set of string, that is to be used as the
72+
* reference dictionary
73+
* @param pos the index value at which we will segment string and test
74+
* further if it is correctly segmented at pos
75+
* @param dp the vector to memoize solution for each position
76+
* @returns `true` if a valid solution/segmentation is possible by segmenting at
77+
* index pos
78+
* @returns `false` otherwise
79+
*/
80+
bool check(const std::string &s, const std::unordered_set<std::string> &strSet,
81+
int pos, std::vector<int> *dp) {
82+
if (pos == s.length()) {
83+
// if we have reached till the end of the string, means we have
84+
// segmented throughout correctly hence we have a solution, thus
85+
// returning true
86+
return true;
87+
}
88+
89+
if (dp->at(pos) != INT_MAX) {
90+
// if dp[pos] is not INT_MAX, means we must have saved a solution
91+
// for the position pos; then return if the solution at pos is true
92+
// or not
93+
return dp->at(pos) == 1;
94+
}
95+
96+
std::string wordTillNow =
97+
""; // string to save the prefixes of word till different positons
98+
99+
for (int i = pos; i < s.length(); i++) {
100+
// Loop starting from pos to end, to check valid set of
101+
// segmentations if any
102+
wordTillNow +=
103+
std::string(1, s[i]); // storing the prefix till the position i
104+
105+
// if the prefix till current position is present in the dictionary
106+
// and the remaining substring can also be segmented legally, then
107+
// set solution at position pos in the memo, and return true
108+
if (exists(wordTillNow, strSet) and check(s, strSet, i + 1, dp)) {
109+
dp->at(pos) = 1;
110+
return true;
111+
}
112+
}
113+
// if function has still not returned, then there must be no legal
114+
// segmentation possible after segmenting at pos
115+
dp->at(pos) = 0; // so set solution at pos as false
116+
return false; // and return no solution at position pos
117+
}
118+
119+
/**
120+
* @brief Function that checks if the string passed in param can be
121+
* segmented into the strings present in the vector.
122+
* In others words, it checks if any permutation of strings in
123+
* the vector can be concatenated to form the final string.
124+
*
125+
* @param s the complete string to be segmented
126+
* @param wordDict a vector of words to be used as dictionary to look into
127+
* @returns `true` if s can be formed by a combination of strings present in
128+
* wordDict
129+
* @return `false` otherwise
130+
*/
131+
bool wordBreak(const std::string &s, const std::vector<std::string> &wordDict) {
132+
// unordered set to store words in the dictionary for constant time
133+
// search
134+
std::unordered_set<std::string> strSet;
135+
for (const auto &s : wordDict) {
136+
strSet.insert(s);
137+
}
138+
// a vector to be used for memoization, whose value at index i will
139+
// tell if the string s can be segmented (correctly) at position i.
140+
// initializing it with INT_MAX (which will denote no solution)
141+
std::vector<int> dp(s.length(), INT_MAX);
142+
143+
// calling check method with position = 0, to check from left
144+
// from where can be start segmenting the complete string in correct
145+
// manner
146+
return check(s, strSet, 0, &dp);
147+
}
148+
149+
} // namespace word_break
150+
} // namespace dynamic_programming
151+
152+
/**
153+
* @brief Test implementations
154+
* @returns void
155+
*/
156+
static void test() {
157+
// the complete string
158+
const std::string s = "applepenapple";
159+
// the dictionary to be used
160+
const std::vector<std::string> wordDict = {"apple", "pen"};
161+
162+
assert(dynamic_programming::word_break::wordBreak(s, wordDict));
163+
164+
// should return true, as applepenapple can be segmented as apple + pen +
165+
// apple
166+
std::cout << dynamic_programming::word_break::wordBreak(s, wordDict)
167+
<< std::endl;
168+
std::cout << "Test implementation passed!\n";
169+
}
170+
/**
171+
* @brief Main function
172+
* @returns 0 on exit
173+
*/
174+
int main() {
175+
test(); // call the test function :)
176+
177+
// the complete string
178+
const std::string s = "applepenapple";
179+
// the dictionary to be used
180+
const std::vector<std::string> wordDict = {"apple", "pen"};
181+
182+
// should return true, as applepenapple can be segmented as apple + pen +
183+
// apple
184+
std::cout << dynamic_programming::word_break::wordBreak(s, wordDict)
185+
<< std::endl;
186+
}

0 commit comments

Comments
 (0)