diff --git a/dynamic_programming/word_break.cpp b/dynamic_programming/word_break.cpp index 14e7c31e4..fcc3b2eb0 100644 --- a/dynamic_programming/word_break.cpp +++ b/dynamic_programming/word_break.cpp @@ -1,28 +1,32 @@ - -/* -Given a non-empty string s and a dictionary wordDict containing a list of -non-empty words, determine if s can be segmented into a space-separated sequence -of one or more dictionary words. - -Note: - -The same word in the dictionary may be reused multiple times in the -segmentation. You may assume the dictionary does not contain duplicate words. -Example 1: - -Input: s = "leetcode", wordDict = ["leet", "code"] -Output: true -Explanation: Return true because "leetcode" can be segmented as "leet code". -Example 2: - -Input: s = "applepenapple", wordDict = ["apple", "pen"] -Output: true -Explanation: Return true because "applepenapple" can be segmented as "apple pen -apple". Note that you are allowed to reuse a dictionary word. Example 3: - -Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] -Output: false -*/ +/** + * @file + * @brief [Word Break Problem] (https://leetcode.com/problems/word-break/) + * @details + * Given a non-empty string s and a dictionary wordDict containing a list of + * non-empty words, determine if s can be segmented into a space-separated + * sequence of one or more dictionary words. + * + * Note: + * The same word in the dictionary may be reused multiple times in the + * segmentation. You may assume the dictionary does not contain duplicate words. + * + * Example 1: + * Input: s = "leetcode", wordDict = ["leet", "code"] + * Output: true + * Explanation: Return true because "leetcode" can be segmented as "leet code". + * + * Example 2: + * Input: s = "applepenapple", wordDict = ["apple", "pen"] + * Output: true + * Explanation: Return true because "applepenapple" can be segmented as "apple + * pen apple". Note that you are allowed to reuse a dictionary word. + * + * Example 3: + * Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] + * Output: false + * + * @author [Akshay Anand] (https://github.com/axayjha) + */ #include #include @@ -30,135 +34,131 @@ Output: false #include #include -using std::cout; -using std::endl; -using std::string; -using std::unordered_set; -using std::vector; - /** * @namespace dynamic_programming * @brief Dynamic programming algorithms */ namespace dynamic_programming { + /** * @namespace word_break * @brief Functions for Word Break algorithm */ namespace word_break { + /** - * @brief Solution class + * @brief Function that checks if the string passed in param is present in + * the the unordered_set passed + * + * @param str the string to be searched + * @param strSet unordered set of string, that is to be looked into + * @returns `true` if str is present in strSet + * @returns `false` otherwise */ -class Solution { - public: - /** - * @brief Function that checks if the string passed in param is present in - * the the unordered_set passed - * - * @param str the string to be searched - * @param strSet unordered set of string, that is to be looked into - * @returns true if str is present in strSet - */ - bool exists(const string &str, const unordered_set &strSet) { - return strSet.find(str) != strSet.end(); +bool exists(const std::string &str, + const std::unordered_set &strSet) { + return strSet.find(str) != strSet.end(); +} + +/** + * @brief Function that checks if the string passed in param can be + * segmented from position 'pos', and then correctly go on to segment the + * rest of the string correctly as well to reach a solution + * + * @param s the complete string to be segmented + * @param strSet unordered set of string, that is to be used as the + * reference dictionary + * @param pos the index value at which we will segment string and test + * further if it is correctly segmented at pos + * @param dp the vector to memoize solution for each position + * @returns `true` if a valid solution/segmentation is possible by segmenting at + * index pos + * @returns `false` otherwise + */ +bool check(const std::string &s, const std::unordered_set &strSet, + int pos, std::vector *dp) { + if (pos == s.length()) { + // if we have reached till the end of the string, means we have + // segmented throughout correctly hence we have a solution, thus + // returning true + return true; } - /** - * @brief Function that checks if the string passed in param can be - * segmented from position 'pos', and then correctly go on to segment the - * rest of the string correctly as well to reach a solution - * - * @param s the complete string to be segmented - * @param strSet unordered set of string, that is to be used as the - * reference dictionary - * @param pos the index value at which we will segment string and test - * further if it is correctly segmented at pos - * @param dp the vector to memoize solution for each position - * @returns `true` if str is present in strSet - * @returns `false` if - */ - bool check(const string &s, const unordered_set &strSet, int pos, - vector *dp) { - if (pos == s.length()) { - // if we have reached till the end of the string, means we have - // segmented throughout correctly hence we have a solution, thus - // returning true + if (dp->at(pos) != INT_MAX) { + // if dp[pos] is not INT_MAX, means we must have saved a solution + // for the position pos; then return if the solution at pos is true + // or not + return dp->at(pos) == 1; + } + + std::string wordTillNow = + ""; // string to save the prefixes of word till different positons + + for (int i = pos; i < s.length(); i++) { + // Loop starting from pos to end, to check valid set of + // segmentations if any + wordTillNow += + std::string(1, s[i]); // storing the prefix till the position i + + // if the prefix till current position is present in the dictionary + // and the remaining substring can also be segmented legally, then + // set solution at position pos in the memo, and return true + if (exists(wordTillNow, strSet) and check(s, strSet, i + 1, dp)) { + dp->at(pos) = 1; return true; } - - if (dp->at(pos) != INT_MAX) { - // if dp[pos] is not INT_MAX, means we must have saved a solution - // for the position pos; then return if the solution at pos is true - // or not - return dp->at(pos) == 1; - } - - string wordTillNow = - ""; // string to save the prefixes of word till different positons - - for (int i = pos; i < s.length(); i++) { - // Loop starting from pos to end, to check valid set of - // segmentations if any - wordTillNow += - string(1, s[i]); // storing the prefix till the position i - - // if the prefix till current position is present in the dictionary - // and the remaining substring can also be segmented legally, then - // set solution at position pos in the memo, and return true - if (exists(wordTillNow, strSet) and check(s, strSet, i + 1, dp)) { - dp->at(pos) = 1; - return true; - } - } - // if function has still not returned, then there must be no legal - // segmentation possible after segmenting at pos - dp->at(pos) = 0; // so set solution at pos as false - return false; // and return no solution at position pos } + // if function has still not returned, then there must be no legal + // segmentation possible after segmenting at pos + dp->at(pos) = 0; // so set solution at pos as false + return false; // and return no solution at position pos +} - /** - * @brief Function that checks if the string passed in param can be - * segmented into the strings present in the vector. - * In others words, it checks if any permutation of strings in - * the vector can be concatenated to form the final string. - * - * @param s the complete string to be segmented - * @param wordDict a vector of words to be used as dictionary to look into - * @returns bool, true if s can be - */ - bool wordBreak(const string &s, const vector &wordDict) { - // unordered set to store words in the dictionary for contant time - // search - unordered_set strSet; - for (const auto &s : wordDict) { - strSet.insert(s); - } - // a vector to be used for memoization, whose value at index i will - // tell if the string s can be segmented (correctly) at position i. - // initializing it with INT_MAX (which will denote no solution) - vector dp(s.length(), INT_MAX); - - // calling check method with position = 0, to check from left - // from where can be start segmenting the complete string in correct - // manner - return check(s, strSet, 0, &dp); +/** + * @brief Function that checks if the string passed in param can be + * segmented into the strings present in the vector. + * In others words, it checks if any permutation of strings in + * the vector can be concatenated to form the final string. + * + * @param s the complete string to be segmented + * @param wordDict a vector of words to be used as dictionary to look into + * @returns `true` if s can be formed by a combination of strings present in + * wordDict + * @return `false` otherwise + */ +bool wordBreak(const std::string &s, const std::vector &wordDict) { + // unordered set to store words in the dictionary for constant time + // search + std::unordered_set strSet; + for (const auto &s : wordDict) { + strSet.insert(s); } -}; + // a vector to be used for memoization, whose value at index i will + // tell if the string s can be segmented (correctly) at position i. + // initializing it with INT_MAX (which will denote no solution) + std::vector dp(s.length(), INT_MAX); + + // calling check method with position = 0, to check from left + // from where can be start segmenting the complete string in correct + // manner + return check(s, strSet, 0, &dp); +} + } // namespace word_break } // namespace dynamic_programming - /** * @brief Main function * @returns 0 on exit */ int main() { // the complete string - const string s = "applepenapple"; + const std::string s = "applepenapple"; // the dictionary to be used - const vector wordDict = {"apple", "pen"}; + const std::vector wordDict = {"apple", "pen"}; // should return true, as applepenapple can be segmented as apple + pen + // apple - cout << dynamic_programming::word_break::Solution().wordBreak(s, wordDict) << endl; + std::cout << dynamic_programming::word_break::wordBreak(s, wordDict) + << std::endl; }