Word Break Problem in DSA Rust - 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.
fn word_break(s: &str, word_dict: &Vec) -> bool {
let n = s.len();
let mut dp = vec![false; n + 1];
dp[0] = true;
for i in 1..=n {
for j in 0..i {
if dp[j] && word_dict.contains(&s[j..i].to_string()) {
dp[i] = true;
break;
}
}
}
dp[n]
}
This code checks if the string s can be split into words from word_dict using dynamic programming.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops checking all substrings and dictionary membership.
- How many times: Outer loop runs
ntimes; inner loop runs up tontimes per outer loop; dictionary lookup inside inner loop.
As the string length n grows, the number of substring checks grows roughly with the square of n.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 100 substring checks |
| 100 | About 10,000 substring checks |
| 1000 | About 1,000,000 substring checks |
Pattern observation: The operations grow roughly like the square of the input size.
Time Complexity: O(n^3)
This means the time needed grows roughly with the cube of the string length because of substring creation and dictionary checks inside nested loops.
[X] Wrong: "The solution runs in O(n^2) because there are only two loops."
[OK] Correct: Each substring check creates a new string and dictionary lookup can take up to O(m) time, adding an extra factor, where m is the length of the substring.
Understanding this complexity helps you explain how dynamic programming solutions handle substring problems efficiently and what limits their speed.
"What if we used a hash set for the dictionary to speed up lookups? How would the time complexity change?"
Practice
Word Break Problem in algorithms?Solution
Step 1: Understand the problem statement
The Word Break Problem asks if a given string can be split into valid words from a dictionary.Step 2: Identify the goal
The goal is to verify if the entire string can be segmented into dictionary words without leftover characters.Final Answer:
To check if a string can be segmented into a sequence of dictionary words -> Option BQuick Check:
Word Break Problem = Check segmentation [OK]
- Confusing with finding longest word
- Thinking it counts characters
- Assuming it reverses strings
Solution
Step 1: Consider dictionary lookup needs
We need fast membership checking to see if a substring is in the dictionary.Step 2: Choose data structure with fast lookup
HashSet provides O(1) average time complexity for lookups, better than Vec or LinkedList.Final Answer:
HashSet<String> -> Option AQuick Check:
Fast lookup = HashSet [OK]
- Using Vec causes slow lookups
- LinkedList is inefficient for search
- BinaryHeap is for priority, not lookup
"applepenapple" and dictionary ["apple", "pen"]?
fn word_break(s: &str, dict: &std::collections::HashSet<&str>) -> bool {
let n = s.len();
let mut dp = vec![false; n + 1];
dp[0] = true;
for i in 1..=n {
for j in 0..i {
if dp[j] && dict.contains(&s[j..i]) {
dp[i] = true;
break;
}
}
}
dp[n]
}
fn main() {
let dict: std::collections::HashSet<&str> = ["apple", "pen"].iter().cloned().collect();
println!("{}", word_break("applepenapple", &dict));
}Solution
Step 1: Understand the dynamic programming logic
The dp array tracks if substring s[0..i] can be segmented. dp[0] is true (empty string).Step 2: Trace substring checks
"apple" and "pen" are in dict, so "applepenapple" can be segmented as "apple" + "pen" + "apple".Final Answer:
true -> Option DQuick Check:
All substrings found = true [OK]
- Assuming false because of repeated words
- Confusing slice indices
- Expecting compilation error due to &str usage
fn word_break(s: &str, dict: &std::collections::HashSet<&str>) -> bool {
let n = s.len();
let mut dp = vec![false; n];
dp[0] = true;
for i in 1..=n {
for j in 0..i {
if dp[j] && dict.contains(&s[j..i]) {
dp[i] = true;
break;
}
}
}
dp[n]
}Solution
Step 1: Check dp vector initialization
dp is initialized with size n, but dp[n] is accessed later, causing out-of-bounds error.Step 2: Correct dp size
dp should be size n+1 to hold dp[0] through dp[n] safely.Final Answer:
dp vector size is incorrect, should be n+1 -> Option CQuick Check:
dp size must cover full string length [OK]
- Ignoring dp out-of-bounds panic
- Changing loop ranges unnecessarily
- Misunderstanding slice syntax
"catsanddog" and dictionary ["cat", "cats", "and", "sand", "dog"], how many different ways can the string be segmented into dictionary words?Solution
Step 1: List possible segmentations
Possible splits are "cats and dog" and "cat sand dog".Step 2: Count valid segmentations
There are exactly 2 ways to segment the string using the dictionary words.Final Answer:
2 -> Option AQuick Check:
Two valid segmentations found [OK]
- Counting partial matches
- Missing one valid segmentation
- Assuming only one way always
Ready to prove it?
Pass the test and this pattern moves unknown
