Rust for Algorithmic Problem-Solving

Parsing Numbers and Strings

Algorithmic problems frequently require parsing integers in arbitrary radices (binary, octal, hexadecimal), indexing strings in $O(1)$ time, and converting between ASCII digits/letters and numeric indices (0..26).

Why Indexing `&str` Directly Is Forbidden in Rust:
  `&str` is UTF-8 (1 to 4 bytes per Unicode scalar `char` -> $O(n)$ `.chars().nth(i)`!)

Solution for $O(1)$ Indexing in Algorithmic String Problems:
  - ASCII strings:       `let bytes: &[u8] = s.as_bytes();`       (1 byte per char, $O(1)$ `bytes[i]`!)
  - Full Unicode chars:  `let chars: Vec<char> = s.chars().collect();` (4 bytes per char, $O(1)$ `chars[i]`!)

1. $O(1)$ String Indexing via .as_bytes() vs Vec<char>

Never call s.chars().nth(i) inside a loop! Because .chars().nth(i) walks UTF-8 bytes from the beginning of the string on every call, a loop for i in 0..n { let c = s.chars().nth(i); } turns an $O(n)$ algorithm into an $O(n^2)$ Time Limit Exceeded (TLE) bug!

Input Guarantee Recommended Representation Random Access s[i] Byte/Char Offset Mapping
ASCII Only ('a'..='z', '0'..='9', symbols) let s = input.as_bytes(); (&[u8] or Vec<u8>) $O(1)$ (s[i]) with 0 heap allocations! (b - b'a') as usize maps 'a'..='z' to 0..26, (b - b'0') maps '0'..='9' to 0..=9.
Arbitrary Multi-Byte Unicode let s: Vec<char> = input.chars().collect(); $O(1)$ (s[i]) (4 bytes per char) (c as u32) Unicode code point.

2. Parsing Integers, Radices, and Byte Slices

pub fn parse_binary_and_hex() {
    // 1. Standard base-10 parsing via `.parse::<T>()` (`FromStr`):
    let decimal: i64 = "-9876543210".parse().unwrap();

    // 2. Parsing arbitrary bases (2..=36) via `from_str_radix`:
    let mask = u32::from_str_radix("1101_0110".replace('_', "").as_str(), 2).unwrap();
    let hex = u64::from_str_radix("deadbeef", 16).unwrap();

    // 3. Converting a single char to a digit in base `R` via `char::to_digit(radix)`:
    let digit_val: u32 = 'f'.to_digit(16).unwrap();
    assert_eq!(digit_val, 15);

    println!("decimal={decimal}, bin={mask:#010b}, hex={hex:#x}, 'f'={digit_val}");
}

/// Ultra-fast unsigned integer parser operating directly on raw ASCII `&[u8]` bytes:
#[inline]
pub fn parse_u64_bytes(bytes: &[u8]) -> u64 {
    bytes
        .iter()
        .fold(0u64, |acc, &b| acc * 10 + u64::from(b - b'0'))
}

/// Converts a lowercase ASCII word into 0..26 alphabet indices in O(n) time:
pub fn word_to_alpha_indices(word: &str) -> Vec<usize> {
    word.as_bytes()
        .iter()
        .map(|&b| (b - b'a') as usize)
        .collect()
}

fn main() {
    parse_binary_and_hex();

    let fast_num = parse_u64_bytes(b"18446744073709551615");
    assert_eq!(fast_num, u64::MAX);

    let indices = word_to_alpha_indices("rust");
    assert_eq!(indices, vec![17, 20, 18, 19]);
    println!("'rust' alphabet indices (0..26): {indices:?}");
}
decimal=-9876543210, bin=0b11010110, hex=0xdeadbeef, 'f'=15
'rust' alphabet indices (0..26): [17, 20, 18, 19]

3. Useful Split and Trim Methods for Structured Input Lines

Input Format Idiomatic Zero-Allocation Parser
Space-separated tokens ("10 20 30\n") s.split_ascii_whitespace()
Comma-separated values ("10,20,30") s.trim().split(',')
Key-value pair ("x=42") let (k, v) = s.trim().split_once('=').unwrap();
Grid of characters (N x M maze) `lines.map(