1. Word Break DP with Full Dictionary
Intuition
Store words in unordered_set<string>. For each word, temporarily remove it. Run standard Word Break DP: dp[i] = true if there exists j such that dp[j] && word.substr(j, i-j) in set. If dp[len] is true, add to result. Reinsert word.
When to apply: Basic baseline check.
Algorithm
- Step 1: Insert all words into a hash set.
- Step 2: For each word, remove from set.
- Step 3: Run
dparray of sizelen + 1:dp[0] = true. - Step 4: For i from 1 to len: check if
dp[j] && word.substr(j, i-j) in set. - Step 5: If
dp[len]is true, add word to result. Re-insert word into set.
#include <iostream>#include <vector>#include <string>#include <unordered_set>using namespace std; class Solution {public: vector<string> findAllConcatenatedWordsInADict(vector<string>& words) { unordered_set<string> dict(words.begin(), words.end()); vector<string> result; for (const string& w : words) { if (w.empty()) continue; dict.erase(w); int len = w.length(); vector<bool> dp(len + 1, false); dp[0] = true; for (int i = 1; i <= len; i++) { for (int j = 0; j < i; j++) { if (dp[j] && dict.count(w.substr(j, i - j))) { dp[i] = true; break; } } } if (dp[len]) result.push_back(w); dict.insert(w); } return result; }}; int main() { Solution sol; vector<string> words = {"cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"}; auto res = sol.findAllConcatenatedWordsInADict(words); for (const string& s : res) cout << s << " "; cout << endl; return 0;}Time & Space Complexity
- Time complexity:
O(N * L^3)— For N words, DP takes O(L2) steps with O(L) string slicing each. - Space complexity:
O(N * L)— Hash set holds all words.
Why Brute Force Doesn't Scale:
With 10,000 words, repeated string allocations cause high GC pressure and TLE.
Trie-based length-sorted segmentation checks 10,000 words in O(N * L2) without a single string slice in ~45ms.