Time: 60 minutes total Questions: 2 coding problems Platform: Language: Rust
- Always: CSV parsing, string manipulation
- Common: Price data (open/high/low/close), CSV ordering
- Skills: Arrays, sorting, basic calculations, formatted output
Variant A: State Simulation (60% of reports)
- Process commands line-by-line from CSV
- State management over time (investment/payment journey)
- Multiple conditional branches
- Financial calculations with precision
Variant B: Complex Data Operations (40% of reports)
- Heavy string manipulation with data structures
- Extensive if-else logic (many branches)
- Sorting and filtering operations
- HashMap-intensive operations
- Time complexity is primary evaluation criterion
- Working but inefficient = poor score
- Think O(n) or O(n log n), avoid O(nΒ²)
- Choose Rust for its performance advantages
- Read BOTH questions first (2 minutes)
- Check test cases immediately (3 minutes)
- Identify harder question - consider tackling it first
- Allocate: Q1 (20-25 min) + Q2 (30-35 min) + buffer (5-10 min)
- β Over-engineering solutions
- β Not checking test cases first
- β Poor time complexity
- β Missing submission steps
use std::collections::{HashMap, BTreeMap, VecDeque};
// HashMap for O(1) lookups
let mut price_map: HashMap<String, f64> = HashMap::new();
// BTreeMap for sorted iteration
// BTreeMap is a map (key-value store) that automatically keeps its keys in sorted order as you insert them.
// You do NOT need to sort it manuallyβiteration over a BTreeMap always yields keys in ascending order.
// This is especially helpful when you need:
// - Output sorted by key (e.g., alphabetically, numerically)
// - Range or prefix queries on sorted data
// Example: Group CSV rows by "Brand" and print in alphabetical order
let mut brand_prices: BTreeMap<String, Vec<f64>> = BTreeMap::new();
for row in csv_rows {
let brand = row[0].to_string();
let price: f64 = row[1].parse().unwrap();
brand_prices.entry(brand).or_default().push(price);
}
for (brand, prices) in brand_prices.iter() {
println!("Brand: {}, Prices: {:?}", brand, prices); // Brands are printed in sorted order
}
// --- Common iteration and range functions (no manual sort needed) ---
// .iter(): Iterate (&key, &value) pairs in ascending (sorted) order
for (key, value) in btreemap.iter() {
// Use sorted key-value pairs
}
// .range(): Iterate over a sorted subset of keys
for (k, v) in btreemap.range("AAPL".to_string()..="MSFT".to_string()) {
// Only keys AAPL to MSFT (inclusive) in sorted order
}
// .values(): Iterate over values in ascending key order
for values in btreemap.values() {
// values, sorted by their keys
}
// .keys(): Iterate over just the keys, in sorted order
for key in btreemap.keys() {
// sorted keys
}
// .into_iter().rev(): Iterate in descending (reverse sorted) order
for (key, value) in btreemap.clone().into_iter().rev() {
// reversed order
}
// NO need to call .sort(): insertion and iteration always use sorted keys!
let mut sorted_data: BTreeMap<String, Vec<f64>> = BTreeMap::new();
// Vec for dynamic arrays
let mut prices: Vec<f64> = Vec::new();
// VecDeque for efficient queue or stack behavior (push/pop at both ends in O(1))
// - Use for simulations that require FIFO or LIFO operations
// Example: processing a stream of events/commands line by line
let mut queue: VecDeque<&str> = VecDeque::new();
queue.push_back("first"); // enqueue
queue.push_front("urgent"); // push to front (LIFO)
let next = queue.pop_front(); // dequeue (FIFO) or pop_front for event processing| Need This Operation | Best Data Structure | Why |
|---|---|---|
| Fast key-based lookups | HashMap<K, V> |
O(1) average lookup time |
| Sorted key iteration | BTreeMap<K, V> |
Automatically maintains sorted order |
| Random access by index | Vec<T> |
O(1) access, O(n) insertion in middle |
| Queue operations (FIFO) | VecDeque<T> |
O(1) push/pop at both ends |
| Stack operations (LIFO) | Vec<T> |
Simple push/pop operations |
| Sorting arbitrary data | Vec<T> + .sort() |
Dedicated sort methods available |
| Grouping/counting | HashMap<K, Vec<T>> |
Efficient grouping by key |
| Ordered unique values | BTreeSet<T> |
Sorted, no duplicates |
Tip: 90% of problems use just Vec, HashMap, and BTreeMap. Start with Vec unless you need key-based access!
// Parse CSV line
let fields: Vec<&str> = line.split(',').collect();
// Trim whitespace on both ends
let trimmed = s.trim();
// Trim whitespace only from left
let left_trimmed = s.trim_start();
// Trim whitespace only from right
let right_trimmed = s.trim_end();
// Joining and splitting
let combined = fields.join(","); // Vec<&str> to String
let fields: Vec<&str> = line.split(',').collect();
// Split on whitespace (most common for command parsing)
let parts: Vec<&str> = line.split_whitespace().collect(); // Removes empty fields
let parts: Vec<&str> = line.split(' ').collect(); // Keeps empty fields from multiple spaces
// Replace/substring
let no_dollar = price_str.replace("$", "");
let first3 = &word[0..3];
// Pattern matching
if value.starts_with("AAPL") {
// Starts with...
}
if value.ends_with(".csv") {
// Ends with...
}
// Parse numbers with error handling
if let Ok(price) = field.parse::<f64>() {
// Use price
}
// Format with precision
format!("${:.2}", amount)// Most common pattern: parse commands with whitespace separation
fn parse_command(line: &str) -> Option<(&str, Vec<f64>)> {
let parts: Vec<&str> = line.trim().split_whitespace().collect();
if parts.is_empty() {
return None;
}
let command = parts[0];
let mut args = Vec::new();
for arg_str in &parts[1..] {
if let Ok(num) = arg_str.parse::<f64>() {
args.push(num);
}
}
Some((command, args))
}
// Example usage:
let line = " SET_INTEREST 5.25 ";
if let Some((cmd, args)) = parse_command(line) {
match cmd {
"SET_INTEREST" => println!("Set interest rate: {:.2}%", args[0]),
"INVEST" => println!("Invest amount: ${:.2}", args[0]),
"TIME" => println!("Advance {} months", args[0] as i32),
_ => println!("Unknown command: {}", cmd),
}
}
// Simple command parsing without validation:
let parts: Vec<&str> = "SET_INTEREST 5.25".split_whitespace().collect();
let command = parts[0]; // "SET_INTEREST"
let rate: f64 = parts[1].parse().unwrap(); // 5.25// .map() - Transform each element
let dollar_prices = vec![12.99, 25.50, 8.75];
let prices_cents: Vec<i64> = dollar_prices.iter()
.map(|&price| (price * 100.0).round() as i64)
.collect();
// Result: [1299, 2550, 875] (exact cents, no floating point errors!)
// .filter() - Keep only elements that match condition
let numbers = vec![1, 2, 3, 4, 5, 6];
let evens: Vec<i32> = numbers.into_iter()
.filter(|&x| x % 2 == 0)
.collect();
// Result: [2, 4, 6]
// Chain them together (very powerful!)
let result: Vec<f64> = vec![10, 20, 30, 40, 50]
.into_iter()
.filter(|&x| x > 25) // Keep numbers > 25
.map(|x| x as f64 * 0.01) // From cents to dollars
.filter(|&x| x < 4.0) // Keep amounts < $4.00
.collect();
// Result: [3.0] (30 * 0.1 = 3.0)
// Real example: Process CSV data
let csv_lines = vec!["AAPL,150.25", "GOOG,2800.50", "INVALID", "MSFT,310.20"];
let valid_prices: Vec<f64> = csv_lines.iter()
.filter_map(|line| {
let parts: Vec<&str> = line.split(',').collect();
if parts.len() == 2 {
parts[1].parse::<f64>().ok()
} else {
None
}
})
.collect();
// Result: [150.25, 2800.50, 310.20] (INVALID filtered out)
// .filter_map() - Filter + Map in one step (returns Option)
let strings = vec!["123", "abc", "456", "def", "789"];
let numbers: Vec<i32> = strings.iter()
.filter_map(|s| s.parse::<i32>().ok()) // Try to parse, filter out failures
.collect();
// Result: [123, 456, 789] (invalid strings filtered out)
// .enumerate() - Get index and value
let names = vec!["AAPL", "GOOG", "MSFT"];
for (index, name) in names.iter().enumerate() {
println!("{}: {}", index, name);
}
// Output: 0: AAPL, 1: GOOG, 2: MSFT
// .zip() - Combine two iterators
let symbols = vec!["AAPL", "GOOG"];
let prices = vec![150.25, 2800.50];
let pairs: Vec<(&str, f64)> = symbols.iter()
.zip(prices.iter())
.map(|(&sym, &price)| (sym, price))
.collect();
// Result: [("AAPL", 150.25), ("GOOG", 2800.50)]Tip: Iterator methods work on all collections! Here's filter_map() with BTreeMap:
// BTreeMap + filter_map() example
let mut prices: BTreeMap<String, f64> = BTreeMap::new();
prices.insert("AAPL".to_string(), 150.25);
prices.insert("GOOG".to_string(), 2800.50);
prices.insert("INVALID".to_string(), -1.0);
// Filter invalid prices and transform (maintains sorted order!)
let valid_prices: Vec<f64> = prices.iter()
.filter_map(|(symbol, &price)| {
if price > 0.0 {
Some(price) // Keep valid prices
} else {
None // Filter out invalid
}
})
.collect();
// Result: [150.25, 2800.50] (AAPL first, then GOOG - sorted!)Iterator methods are often more efficient and readable than manual loops. Use .filter_map() for parsing operations that might fail!
// has NO date/time libraries - only string manipulation!
// Convert "HH:MM" to minutes since midnight for comparison/arithmetic
fn time_to_minutes(time_str: &str) -> Option<i32> {
let parts: Vec<&str> = time_str.split(':').collect();
if parts.len() == 2 {
if let (Ok(hours), Ok(minutes)) = (parts[0].parse::<i32>(), parts[1].parse::<i32>()) {
if hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60 {
return Some(hours * 60 + minutes);
}
}
}
None
}
fn minutes_to_time(minutes: i32) -> String {
let hours = minutes / 60;
let mins = minutes % 60;
format!("{:02}:{:02}", hours, mins)
}
// Usage examples:
let time1 = "09:30"; // 9:30 AM
let time2 = "14:45"; // 2:45 PM
if let (Some(min1), Some(min2)) = (time_to_minutes(time1), time_to_minutes(time2)) {
// Compare times
if min1 < min2 {
println!("{} is before {}", time1, time2);
}
// Calculate duration
let duration = min2 - min1; // in minutes
println!("Duration: {} minutes", duration);
// Add time
let new_time = minutes_to_time(min1 + 120); // Add 2 hours
println!("2 hours later: {}", new_time);
}
// Sorting times
let times = vec!["14:30", "09:15", "11:45"];
let mut time_minutes: Vec<(i32, &str)> = times.iter()
.filter_map(|&t| time_to_minutes(t).map(|m| (m, t)))
.collect();
time_minutes.sort_by_key(|&(mins, _)| mins);
println!("Sorted times:");
for (_, time_str) in time_minutes {
println!("{}", time_str);
}Reality: No chrono, no DateTime - only string parsing and minute arithmetic!
use std::collections::BTreeSet;
// BTreeSet doesn't have .map() directly - use iterator + collect
let dollar_amounts: BTreeSet<f64> = [12.99, 25.50, 8.75, 12.99].into(); // Duplicates removed
// Convert dollars to cents (i64)
let cent_amounts: BTreeSet<i64> = dollar_amounts.into_iter()
.map(|dollars| (dollars * 100.0).round() as i64)
.collect();
// Result: {875, 1299, 2550} (sorted, unique cents)
// Mutable version: Start with dollars, transform to cents
let mut dollar_set: BTreeSet<f64> = BTreeSet::new();
dollar_set.insert(12.99);
dollar_set.insert(25.50);
dollar_set.insert(8.75);
// Transform to cents set
let cent_set: BTreeSet<i64> = dollar_set.into_iter()
.map(|price| (price * 100.0).round() as i64)
.collect();
println!("Cents: {:?}", cent_set); // {875, 1299, 2550}
// BTreeMap transformation (transform values, keep keys)
let mut price_map: BTreeMap<String, f64> = BTreeMap::new();
price_map.insert("AAPL".to_string(), 150.25);
price_map.insert("GOOG".to_string(), 2800.50);
// Transform values to cents, keep same keys
let cent_map: BTreeMap<String, i64> = price_map.into_iter()
.map(|(symbol, price)| (symbol, (price * 100.0).round() as i64))
.collect();
println!("Cent prices: {:?}", cent_map);
// {"AAPL": 15025, "GOOG": 280050} (sorted by symbol!)
// Alternative: Transform both keys and values
let symbol_to_cents: BTreeMap<String, i64> = price_map.into_iter()
.map(|(symbol, price)| (symbol.to_uppercase(), (price * 100.0).round() as i64))
.collect();
// Transform only keys (values stay the same)
let upper_case_map: BTreeMap<String, f64> = price_map.into_iter()
.map(|(symbol, price)| (symbol.to_uppercase(), price))
.collect();
// {"AAPL": 150.25, "GOOG": 2800.50}
// Filter + Transform: Keep only expensive stocks, convert to cents
let expensive_stocks: BTreeMap<String, i64> = price_map.into_iter()
.filter(|(_, &price)| price > 1000.0) // Keep only > $1000
.map(|(symbol, price)| (symbol, (price * 100.0).round() as i64))
.collect();
// {"GOOG": 280050} (only GOOG qualifies)
// Transform to different value type entirely
let stock_info: BTreeMap<String, String> = price_map.into_iter()
.map(|(symbol, price)| {
let cents = (price * 100.0).round() as i64;
(symbol, format!("${:.2} ({} cents)", price, cents))
})
.collect();
// {"AAPL": "$150.25 (15025 cents)", "GOOG": "$2800.50 (280050 cents)"}// For f64 to i64 conversion specifically
fn convert_prices_to_cents(prices: BTreeMap<String, f64>) -> BTreeMap<String, i64> {
prices.into_iter()
.map(|(symbol, price)| (symbol, (price * 100.0).round() as i64))
.collect()
}fn process_csv(csv_data: &str) -> String {
let lines: Vec<&str> = csv_data.trim().split('\n').collect();
let mut result = Vec::new();
for line in &lines[1..] { // Skip header
let fields: Vec<&str> = line.split(',').collect();
// Process fields...
}
result.join("\n")
}use std::fs;
use std::io::{self, BufRead};
// Read entire CSV file into string (simple approach)
fn read_csv_file_simple(filename: &str) -> Result<String, io::Error> {
fs::read_to_string(filename)
}
// Read CSV line by line (memory efficient for large files)
fn read_csv_file_efficient(filename: &str) -> Result<Vec<String>, io::Error> {
let file = fs::File::open(filename)?;
let reader = io::BufReader::new(file);
let mut lines = Vec::new();
for line in reader.lines() {
lines.push(line?);
}
Ok(lines)
}
// Process CSV file directly
fn process_csv_file(filename: &str) -> Result<String, io::Error> {
let content = fs::read_to_string(filename)?;
// Now process like normal CSV string
let lines: Vec<&str> = content.trim().split('\n').collect();
let mut result = Vec::new();
for line in &lines[1..] { // Skip header
let fields: Vec<&str> = line.split(',').collect();
// Process fields...
result.push(fields.join(",")); // Example
}
Ok(result.join("\n"))
}Note: provides CSV data as string parameters, so you won't need file I/O. This is just for reference if you encounter file-based problems elsewhere.
- Read Question 1 completely
- Read Question 2 completely
- Note key requirements and constraints
- Assess difficulty - which seems harder?
- Check test cases for both questions
- Understand exact input/output format
- Think algorithm efficiency first
- Decide question order (consider harder first)
- Start with chosen question
- Write clean, readable Rust code
- Test frequently as you code
- Focus on correctness first, then optimize
- Test edge cases
- Review code for clarity
- Click "Submit test"
- Click "Finish test" (CRITICAL - don't miss this!)
- Don't panic - focus on simpler question if stuck
- Check test cases - they guide the solution
- Simple efficient solution > perfect incomplete code
- Re-read the problem carefully
- Look at test cases again
- Break problem into smaller steps
- Consider edge cases
- Brute force may pass small tests but score poorly
- Think: Can I do this in O(n) instead of O(nΒ²)?
- HashMap lookups are O(1), sorting is O(n log n)
- Parse lines, split by commas
- Handle headers separately
- Use HashMap for grouping by key
- BTreeMap for sorted output
- Define clear state struct
- Process commands in loop
- Update state based on command type
- Validate state transitions
- Use f64 for precision
- Round to 2 decimal places when required
- Handle compound interest carefully
- Watch for floating-point precision issues
Simple Interest (One-time application):
// Interest rate: 5.25% on $1000
let principal = 1000.0;
let rate_percent = 5.25;
let multiplier = 1.0 + (rate_percent / 100.0); // 1.0525
let result = principal * multiplier; // $1052.50Compound Interest (Multiple applications):
// Command sequence: ["DEPOSIT 1000.00", "INTEREST 5.25", "COMPOUND"]
let balance = 1000.0;
let rate = 5.25;
// First INTEREST command
balance = balance * (1.0 + rate/100.0); // $1052.50
// Later COMPOUND command (applies same rate again)
balance = balance * (1.0 + rate/100.0); // $1107.56
// Multiple compounding periods
for _ in 0..periods {
balance = balance * (1.0 + rate/100.0);
}Common Patterns:
INTEREST rateβ Sets rate AND applies interest immediatelyCOMPOUNDβ Applies previously set interest rate again- Store
interest_rateas instance variable between commands - Always use
.round()for financial precision
β Common f64 Problems:
// PITFALL: Floating point can't represent 0.1 exactly
let price = 0.1 + 0.2; // 0.30000000000000004, not 0.3!
// PITFALL: Accumulating errors in loops
let mut total = 0.0;
for _ in 0..10 {
total += 0.1; // total might be 0.9999999999999999, not 1.0!
}
// PITFALL: Comparison issues
if total == 1.0 { /* This might never be true! */ }β Solutions for :
- Use Integer Arithmetic for Money (See
financial_calculations.rs):
// Store money as cents (i32) or with fixed precision
let price_cents = 299; // $2.99
let total_cents = price_cents * 3; // 897 cents = $8.97
// For display
println!("${:.2}", total_cents as f64 / 100.0);- Round at Critical Points:
let result = (calculation * 100.0).round() / 100.0; // Round to 2 decimals- Avoid Direct Equality:
// Instead of: if amount == 0.0
if (amount * 100.0).round() == 0.0 { /* Check for zero */ }
// Or use epsilon comparison
const EPSILON: f64 = 0.001;
if (amount - target).abs() < EPSILON { /* Close enough */ }- Use PreciseDecimal Pattern (from practice code):
const PRECISION: i64 = 100; // 2 decimal places
#[derive(Clone)]
struct Money {
cents: i64, // Store as integer
}
impl Money {
fn new(amount: f64) -> Self {
Money { cents: (amount * PRECISION as f64).round() as i64 }
}
fn to_f64(&self) -> f64 {
self.cents as f64 / PRECISION as f64
}
fn add(&self, other: &Money) -> Money {
Money { cents: self.cents + other.cents }
}
}Tip: For financial problems, expect exact 2-decimal precision. Use rounding and avoid direct f64 equality checks!
- Practice all pattern types
- Know Rust standard library well
- Can write efficient algorithms quickly
- Comfortable with time pressure
- Read both questions first
- Check test cases immediately
- Focus on algorithm efficiency
- Write clean, working code
- Test frequently
- Click "Submit test"
- Click "Finish test" (CRITICAL!)
- Don't forget either step
Remember: Algorithm efficiency + clean code wins. The problems themselves aren't extremely hard - doing them optimally is the real challenge. You have the Rust skills and practice - focus on efficiency and you'll succeed!
Good luck! You've got this. π