Roman to Integer Conversion in DSA Rust - Time & Space Complexity
We want to know how the time to convert a Roman numeral to an integer grows as the input gets longer.
How does the number of steps change when the Roman numeral string is bigger?
Analyze the time complexity of the following code snippet.
fn roman_to_int(s: &str) -> i32 {
let mut total = 0;
let mut prev = 0;
for c in s.chars().rev() {
let value = match c {
'I' => 1,
'V' => 5,
'X' => 10,
'L' => 50,
'C' => 100,
'D' => 500,
'M' => 1000,
_ => 0,
};
if value < prev {
total -= value;
} else {
total += value;
}
prev = value;
}
total
}
This code converts a Roman numeral string to an integer by reading characters from right to left and adding or subtracting values.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through each character of the input string once.
- How many times: Exactly once for each character in the string.
As the Roman numeral string gets longer, the number of steps grows directly with its length.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The steps increase in a straight line as input size grows.
Time Complexity: O(n)
This means the time to convert grows directly with the length of the Roman numeral string.
[X] Wrong: "The code does multiple passes or nested loops, so it must be slower than linear."
[OK] Correct: The code only loops once through the string, doing simple checks each time, so it is linear time.
Understanding this helps you explain how to efficiently process strings character by character, a common skill in coding interviews.
"What if we changed the code to use recursion instead of a loop? How would the time complexity change?"
Practice
Solution
Step 1: Understand Roman numeral rules
Roman numerals are added normally, but if a smaller numeral appears before a larger one, it is subtracted.Step 2: Apply the rule to conversion
When converting, add each symbol's value unless a smaller symbol precedes a larger one, then subtract the smaller.Final Answer:
Add values of symbols, subtract if a smaller symbol is before a larger one -> Option BQuick Check:
Roman to integer = add or subtract based on order [OK]
- Always adding without subtraction
- Multiplying values instead of adding
- Ignoring order of symbols
Solution
Step 1: Check Rust function syntax
Rust functions start with fn, use snake_case, and specify parameter types and return type correctly.Step 2: Validate each option
fn roman_to_int(s: &str) -> i32 { uses correct Rust syntax: fn, snake_case, &str parameter, and i32 return type. Others have syntax errors or wrong types.Final Answer:
fn roman_to_int(s: &str) -> i32 { -> Option AQuick Check:
Rust fn header with &str and i32 return [OK]
- Using camelCase instead of snake_case
- Wrong parameter or return types
- Using 'function' keyword (not Rust)
fn main() {
let s = "IX";
let result = roman_to_int(s);
println!("{}", result);
}
fn roman_to_int(s: &str) -> i32 {
let mut total = 0;
let mut prev = 0;
for c in s.chars().rev() {
let value = match c {
'I' => 1,
'V' => 5,
'X' => 10,
_ => 0,
};
if value < prev {
total -= value;
} else {
total += value;
}
prev = value;
}
total
}Solution
Step 1: Trace characters in reverse
Input "IX" reversed is 'X' then 'I'. 'X' = 10, 'I' = 1.Step 2: Calculate total with subtraction rule
Start total=0, prev=0. 'X' (10) >= prev(0), total=10, prev=10. Next 'I' (1) < prev(10), total=10-1=9, prev=1.Final Answer:
9 -> Option DQuick Check:
"IX" = 9 [OK]
- Not reversing string for correct subtraction
- Adding all values without subtraction
- Misassigning values to characters
fn roman_to_int(s: &str) -> i32 {
let mut total = 0;
let mut prev = 0;
for c in s.chars() {
let value = match c {
'I' => 1,
'V' => 5,
'X' => 10,
_ => 0,
};
if value > prev {
total += value - 2 * prev;
} else {
total += value;
}
prev = value;
}
total
}Solution
Step 1: Inspect the match expression
The match only handles 'I'(1), 'V'(5), 'X'(10). It misses 'L'(50), 'C'(100), 'D'(500), 'M'(1000), causing other symbols to map to 0 and produce wrong results.Step 2: Verify other options
A: Forward iteration with 'value - 2*prev' is valid for handling subtractive notation. B: The 2*prev subtraction corrects the previously added prev value. D: 'prev' is already mutable.Final Answer:
Match arms missing some Roman numerals -> Option CQuick Check:
Match must cover I,V,X,L,C,D,M [OK]
- Incomplete match arms
- Not handling all Roman numerals
- Forgetting to make prev mutable (already mutable here)
fn roman_to_int(s: &str) -> i32 {
let mut total = 0;
let mut prev = 0;
for c in s.chars().rev() {
let value = match c {
'I' => 1,
'V' => 5,
'X' => 10,
'L' => 50,
'C' => 100,
'D' => 500,
'M' => 1000,
_ => 0,
};
if value < prev {
total -= value;
} else {
total += value;
}
prev = value;
}
total
}Solution
Step 1: Reverse and assign values
Reverse "MCMXCIV" to "VICXMCM". Values: V=5, I=1, C=100, X=10, M=1000, C=100, M=1000.Step 2: Calculate total with subtraction rule
Start total=0, prev=0. - V(5) >= prev(0): total=5, prev=5 - I(1) < prev(5): total=5-1=4, prev=1 - C(100) >= prev(1): total=4+100=104, prev=100 - X(10) < prev(100): total=104-10=94, prev=10 - M(1000) >= prev(10): total=94+1000=1094, prev=1000 - C(100) < prev(1000): total=1094-100=994, prev=100 - M(1000) >= prev(100): total=994+1000=1994, prev=1000Final Answer:
1994 -> Option AQuick Check:
"MCMXCIV" = 1994 [OK]
- Not reversing string before processing
- Misassigning values to symbols
- Ignoring subtraction rule
Ready to prove it?
Pass the test and this pattern moves unknown
