TheAlgorithms-C-Plus-Plus/dynamic_programming/word_break.cpp

151 lines
5.3 KiB
C++
Raw Normal View History

2020-10-14 12:52:55 +08:00
/*
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
*/
2020-10-14 13:15:12 +08:00
#include <climits>
2020-10-14 12:52:55 +08:00
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>
2020-10-14 13:08:22 +08:00
using std::cout;
using std::endl;
using std::string;
using std::unordered_set;
using std::vector;
2020-10-14 12:52:55 +08:00
/**
* @brief Solution class
*/
2020-10-14 12:52:55 +08:00
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<string> &strSet) {
return strSet.find(str) != strSet.end();
2020-10-14 12:52:55 +08:00
}
/**
* @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 bool, true if str is present in strSet
*/
2020-10-14 13:15:12 +08:00
bool check(const string &s, const unordered_set<string> &strSet, int pos,
vector<int> *dp) {
2020-10-14 12:52:55 +08:00
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
2020-10-14 12:52:55 +08:00
return true;
}
2020-10-14 13:15:12 +08:00
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
2020-10-14 13:15:12 +08:00
return dp->at(pos) == 1;
2020-10-14 12:52:55 +08:00
}
string wordTillNow =
""; // string to save the prefixes of word till different positons
2020-10-14 12:52:55 +08:00
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
2020-10-14 12:52:55 +08:00
if (exists(wordTillNow, strSet) and check(s, strSet, i + 1, dp)) {
2020-10-14 13:15:12 +08:00
dp->at(pos) = 1;
2020-10-14 12:52:55 +08:00
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
2020-10-14 12:52:55 +08:00
}
/**
* @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
*/
2020-10-14 13:15:12 +08:00
bool wordBreak(const string &s, const vector<string> &wordDict) {
// unordered set to store words in the dictionary for contant time
// search
2020-10-14 12:52:55 +08:00
unordered_set<string> strSet;
2020-10-14 13:15:12 +08:00
for (const auto &s : wordDict) {
2020-10-14 12:52:55 +08:00
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)
2020-10-14 12:52:55 +08:00
vector<int> 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
2020-10-14 13:15:12 +08:00
return check(s, strSet, 0, &dp);
2020-10-14 12:52:55 +08:00
}
};
2020-10-14 13:08:22 +08:00
/**
* @brief Main function
* @returns 0 on exit
*/
2020-10-14 13:08:22 +08:00
int main() {
// the complete string
2020-10-14 13:08:22 +08:00
const string s = "applepenapple";
// the dictionary to be used
2020-10-14 13:08:22 +08:00
const vector<string> wordDict = {"apple", "pen"};
// should return true, as applepenapple can be segmented as apple + pen +
// apple
2020-10-14 13:08:22 +08:00
cout << Solution().wordBreak(s, wordDict) << endl;
}