Word Break Problem in DSA C++ - Time & Space Complexity
We want to understand how the time needed to solve the Word Break Problem changes as the input grows.
Specifically, how does checking if a string can be split into dictionary words scale with string length?
Analyze the time complexity of the following code snippet.
bool wordBreak(string s, unordered_set<string> &dict) {
int n = s.size();
vector<bool> dp(n + 1, false);
dp[0] = true;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && dict.count(s.substr(j, i - j))) {
dp[i] = true;
break;
}
}
}
return dp[n];
}
This code checks if the string can be segmented into dictionary words using dynamic programming.
- Primary operation: Nested loops where the outer loop runs from 1 to n and the inner loop runs from 0 to i-1.
- How many times: The inner loop runs approximately i times for each i, so total checks are about 1 + 2 + ... + n = n(n+1)/2 times.
- Substring checks: Each iteration extracts a substring and checks if it is in the dictionary.
As the string length grows, the number of substring checks grows roughly with the square of the length.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 55 substring checks |
| 100 | About 5,050 substring checks |
| 1000 | About 500,500 substring checks |
Pattern observation: The operations grow roughly like n squared, meaning doubling the input length roughly quadruples the work.
Time Complexity: O(n^3)
This means the time grows roughly with the cube of the string length due to substring extraction and dictionary lookups.
[X] Wrong: "The algorithm runs in linear time because it uses dynamic programming."
[OK] Correct: Although dynamic programming avoids repeated work, the nested loops still check many substrings, causing cubic growth, not linear.
Understanding this time complexity helps you explain how dynamic programming improves efficiency and why nested loops impact performance.
"What if we used a Trie data structure for the dictionary lookups instead of a hash set? How would the time complexity change?"
Practice
s and a dictionary of words wordDict?Solution
Step 1: Understand the problem statement
The Word Break Problem asks if the entire stringscan be split into parts where each part is a word from the dictionarywordDict.Step 2: Differentiate from similar concepts
It is not enough forsto contain a dictionary word or be equal to one; the whole string must be fully segmented into dictionary words.Final Answer:
Ifscan be segmented into a sequence of dictionary words -> Option CQuick Check:
Word Break = Full segmentation check [OK]
- Thinking partial substring match is enough
- Confusing exact match with segmentation
- Ignoring the order of words in segmentation
wordBreak that takes a string s and a vector<string> named wordDict and returns a bool?Solution
Step 1: Understand parameter passing in C++
Passingvector<string>by reference requires the ampersand&after the type, with optional space before the variable name.Step 2: Check syntax correctness
bool wordBreak(string s, vector<string> &wordDict); correctly places the ampersand before the parameter name with a space:vector<string> &wordDict. bool wordBreak(string s, vector<string>& wordDict); is also valid but less common spacing. bool wordBreak(string s, vector<string> wordDict&); is invalid syntax.Final Answer:
bool wordBreak(string s, vector<string> &wordDict); -> Option AQuick Check:
Reference parameter syntax = bool wordBreak(string s, vector<string> &wordDict); [OK]
- Placing & after variable name incorrectly
- Missing semicolon at function declaration
- Using invalid syntax like wordDict&
bool wordBreak(string s, vector<string> &wordDict) {
unordered_set<string> dict(wordDict.begin(), wordDict.end());
vector<bool> dp(s.size() + 1, false);
dp[0] = true;
for (int i = 1; i <= s.size(); i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && dict.count(s.substr(j, i - j))) {
dp[i] = true;
break;
}
}
}
return dp[s.size()];
}
int main() {
string s = "leetcode";
vector<string> wordDict = {"leet", "code"};
cout << (wordBreak(s, wordDict) ? "true" : "false") << endl;
return 0;
}Solution
Step 1: Understand the dynamic programming logic
The code uses a boolean vectordpwheredp[i]is true if substrings[0..i-1]can be segmented into dictionary words. It initializesdp[0]as true (empty string).Step 2: Trace the example input "leetcode" with dictionary ["leet", "code"]
At i=4, substring "leet" is in dictionary, sodp[4]= true. At i=8, substring "code" is in dictionary anddp[4]is true, sodp[8]= true. Finally,dp[s.size()]= true.Final Answer:
true -> Option AQuick Check:
DP segmentation confirms full string = true [OK]
- Confusing substring indices
- Forgetting to break inner loop after true
- Misunderstanding dp initialization
bool wordBreak(string s, vector<string> &wordDict) {
unordered_set<string> dict(wordDict.begin(), wordDict.end());
vector<bool> dp(s.size(), false);
dp[0] = true;
for (int i = 1; i <= s.size(); i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && dict.count(s.substr(j, i - j))) {
dp[i] = true;
break;
}
}
}
return dp[s.size()];
}Solution
Step 1: Check dp vector size and indexing
The dp vector is sized tos.size(), but the code accessesdp[s.size()]which is out of bounds. It should be sizeds.size() + 1to include the base case for empty substring.Step 2: Verify other parts
unordered_set usage and substring indices are correct. dp[0] must be true to represent empty string segmentation.Final Answer:
dp vector size should be s.size() + 1, not s.size() -> Option BQuick Check:
dp size off by one causes runtime error [OK]
- Using dp size equal to string length only
- Misinitializing dp[0] to false
- Confusing substring parameters
s = "applepenapple" and dictionary wordDict = ["apple", "pen"], which of the following modifications to the Word Break algorithm allows it to also return the actual segmented sentence "apple pen apple" instead of just true or false?Solution
Step 1: Understand the limitation of boolean DP
The standard Word Break DP returns only true/false indicating if segmentation is possible, but does not store the actual segmented sentences.Step 2: Modify DP to store sentences
By using a vector of strings at each dp index, we can store all possible sentences formed up to that index. When a valid word is found, append it to sentences from previous indices.Step 3: Final answer
This approach allows reconstructing the segmented sentence like "apple pen apple".Final Answer:
Use a vector of strings to store sentences at each index and build them during DP -> Option DQuick Check:
Store sentences in DP to reconstruct output [OK]
- Trying to modify dictionary words
- Returning count instead of sentences
- Using stack without DP sentence storage
Ready to prove it?
Pass the test and this pattern moves unknown
