Best Rust Coding Interview Questions for Beginners

2025-08-19

Rust is gaining popularity in systems programming, backend engineering, and even interviews. While most companies still test you with language-agnostic problems, being comfortable solving them in Rust can help you stand out. Below are beginner-friendly Rust coding interview questions, with real solutions and explanations.


1) Two Sum

Concepts: Hash maps, ownership, borrowing.

use std::collections::HashMap;

fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
    let mut map = HashMap::new();
    for (i, &n) in nums.iter().enumerate() {
        let need = target - n;
        if let Some(&j) = map.get(&need) {
            return vec![j as i32, i as i32];
        }
        map.insert(n, i);
    }
    vec![]
}

fn main() {
    println!("{:?}", two_sum(vec![2,7,11,15], 9)); // [0,1]
}

2) Reverse a String

Concepts: Iterators, string handling.

fn reverse_string(s: &str) -> String {
    s.chars().rev().collect()
}

fn main() {
    println!("{}", reverse_string("rustacean")); // "naecatsur"
}

3) Palindrome Number

Concepts: Converting to string, iterator tricks.

fn is_palindrome(x: i32) -> bool {
    let s = x.to_string();
    s.chars().eq(s.chars().rev())
}

fn main() {
    println!("{}", is_palindrome(121)); // true
    println!("{}", is_palindrome(-121)); // false
}

4) FizzBuzz

Concepts: Pattern matching, loops.

fn fizz_buzz(n: i32) -> Vec<String> {
    (1..=n)
        .map(|i| match (i % 3, i % 5) {
            (0, 0) => "FizzBuzz".to_string(),
            (0, _) => "Fizz".to_string(),
            (_, 0) => "Buzz".to_string(),
            _ => i.to_string(),
        })
        .collect()
}

fn main() {
    println!("{:?}", fizz_buzz(15));
}

5) Maximum Subarray (Kadane’s Algorithm)

Concepts: Iteration with state, std::cmp::max.

fn max_sub_array(nums: Vec<i32>) -> i32 {
    let mut cur = nums[0];
    let mut best = nums[0];
    for &n in &nums[1..] {
        cur = std::cmp::max(n, cur + n);
        best = std::cmp::max(best, cur);
    }
    best
}

fn main() {
    println!("{}", max_sub_array(vec![-2,1,-3,4,-1,2,1,-5,4])); // 6
}

6) Merge Two Sorted Lists

Concepts: Linked lists, Option<Box<T>>.

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>,
}

impl ListNode {
    fn new(val: i32) -> Self {
        ListNode { val, next: None }
    }
}

fn merge_two_lists(
    l1: Option<Box<ListNode>>,
    l2: Option<Box<ListNode>>,
) -> Option<Box<ListNode>> {
    match (l1, l2) {
        (Some(mut n1), Some(mut n2)) => {
            if n1.val < n2.val {
                n1.next = merge_two_lists(n1.next.take(), Some(n2));
                Some(n1)
            } else {
                n2.next = merge_two_lists(Some(n1), n2.next.take());
                Some(n2)
            }
        }
        (None, l) => l,
        (l, None) => l,
    }
}

7) Valid Parentheses

Concepts: Stack, vectors.

fn is_valid(s: String) -> bool {
    let mut stack = Vec::new();
    for c in s.chars() {
        match c {
            '(' | '{' | '[' => stack.push(c),
            ')' => if stack.pop() != Some('(') { return false; },
            '}' => if stack.pop() != Some('{') { return false; },
            ']' => if stack.pop() != Some('[') { return false; },
            _ => {}
        }
    }
    stack.is_empty()
}

fn main() {
    println!("{}", is_valid("()[]{}".to_string())); // true
    println!("{}", is_valid("(]".to_string())); // false
}

8) Climbing Stairs

Concepts: DP, iterative state.

fn climb_stairs(n: i32) -> i32 {
    if n <= 2 { return n; }
    let mut a = 1;
    let mut b = 2;
    for _ in 3..=n {
        let c = a + b;
        a = b;
        b = c;
    }
    b
}

fn main() {
    println!("{}", climb_stairs(5)); // 8
}

9) Binary Search

Concepts: Loops, bounds handling.

fn binary_search(nums: &[i32], target: i32) -> i32 {
    let mut lo = 0;
    let mut hi = nums.len() as i32 - 1;
    while lo <= hi {
        let mid = lo + (hi - lo) / 2;
        if nums[mid as usize] == target { return mid; }
        if nums[mid as usize] < target { lo = mid + 1; }
        else { hi = mid - 1; }
    }
    -1
}

fn main() {
    println!("{}", binary_search(&[1,3,5,7,9], 7)); // 3
}

10) Breadth-First Search (BFS) on a Graph

Concepts: Queue with VecDeque.

use std::collections::VecDeque;

fn bfs(n: usize, edges: &[(usize, usize)], start: usize) -> Vec<usize> {
    let mut graph = vec![vec![]; n];
    for &(u, v) in edges {
        graph[u].push(v);
        graph[v].push(u);
    }

    let mut visited = vec![false; n];
    let mut order = Vec::new();
    let mut q = VecDeque::new();
    q.push_back(start);
    visited[start] = true;

    while let Some(u) = q.pop_front() {
        order.push(u);
        for &v in &graph[u] {
            if !visited[v] {
                visited[v] = true;
                q.push_back(v);
            }
        }
    }
    order
}

fn main() {
    let edges = [(0,1),(0,2),(1,3),(1,4)];
    println!("{:?}", bfs(5, &edges, 0)); // [0,1,2,3,4]
}

Interview Checklist for Rust Beginners

  • Be ready to explain ownership and borrowing when passing data structures.
  • Prefer iterators and pattern matching over verbose loops.
  • Use Option/Result idiomatically for null/error handling.
  • Keep solutions clean with collect(), enumerate(), map(), and zip().
  • For data structures, know how to use Vec, HashMap, HashSet, VecDeque.

Final Note

Learning LeetCode in Rust trains both your algorithmic thinking and your ability to use Rust’s unique features. Mastering these beginner problems will prepare you for tougher DP, graph, and system design challenges.

If you want to see clean Rust solutions live while you practice, check out StealthCoder — it can overlay working code and explanations so you can stay focused and build confidence.