Coding Tasks
Hands-on C# coding tasks — string and array algorithms, recursion, and in-place tricks.
6 questions
JuniorCodeVery commonReverse a char[] in place in O(n) time and O(1) space
Reverse a char[] in place in O(n) time and O(1) space
Two indices l = 0 and r = s.Length - 1. While l < r, swap s[l] and s[r] (a tuple swap (s[l], s[r]) = (s[r], s[l])), then l++ and r--. The loop ends when they cross, reversing in place. O(n) time, O(1) extra space.
Common mistakes
- ✗Looping all the way to the end and swapping twice, which restores the original order
- ✗Allocating a second array, violating the O(1) extra-space requirement
- ✗Returning a new value instead of mutating the passed-in array in place
Follow-up questions
- →Why must the loop stop at
l < rand not run to the end? - →How would surrogate pairs (emoji) break a naive per-
charreversal?
JuniorCodeCommonFind the nth Fibonacci number iteratively in O(n) time, O(1) space
Find the nth Fibonacci number iteratively in O(n) time, O(1) space
Keep two rolling values a = 0, b = 1. Loop n times: compute b as a + b and shift a to the old b via a tuple update (a, b) = (b, a + b). Return a. This is O(n) time, O(1) space — no array and no exponential recursion.
Common mistakes
- ✗Using naive double recursion, which is exponential O(2^n), not O(n)
- ✗Allocating an array of all n values, wasting O(n) space when O(1) suffices
- ✗Off-by-one in the loop so
Fib(0)orFib(1)returns the wrong seed value
Follow-up questions
- →Why is naive recursion exponential, and how does memoization fix it?
- →At what
ndoesFiboverflowlong?
JuniorCodeCommonCheck a string is a palindrome in O(n), ignoring case and non-letters
Check a string is a palindrome in O(n), ignoring case and non-letters
Two pointers l = 0 and r = s.Length - 1 moving inward. Skip any character where char.IsLetter is false on either side, then compare with char.ToLower; mismatch returns false. Meeting in the middle returns true. O(n) time, O(1) extra space.
Common mistakes
- ✗Building a cleaned/reversed copy, which costs O(n) extra space instead of O(1)
- ✗Comparing characters without normalizing case via
char.ToLower - ✗Forgetting to skip non-letters on BOTH sides before each comparison
Follow-up questions
- →How would you also treat digits as significant characters?
- →Why does skipping non-letters inside the loop keep it O(n) overall?
MiddleCodeCommonRemove duplicates from an array, preserving first-seen order, in O(n)
Remove duplicates from an array, preserving first-seen order, in O(n)
Walk nums once with a HashSet<int> seen and a List<int> result. For each value, seen.Add(n) returns false if already present — skip it; on true, append to result. Return result.ToArray(). The set gives O(1) membership, so the whole pass is O(n) and order is preserved.
Common mistakes
- ✗Sorting first, which destroys the required first-seen order
- ✗Using a nested-loop membership check, making it O(n²) instead of O(n)
- ✗Returning
set.ToArray()directly, which gives no guaranteed insertion order
Follow-up questions
- →Why does
HashSet.Addreturning a bool save you a separateContainscall? - →How would you dedupe a stream too large to fit in memory?
JuniorCodeOccasionalCompute n! recursively, accounting for overflow
Compute n! recursively, accounting for overflow
Recurse: the base case n <= 1 returns 1 (covers 0 and 1); otherwise return n * Factorial(n - 1). Cast to long so the product widens early. Because 21! overflows long, wrap the multiply in checked to throw rather than silently wrap. O(n) calls.
Common mistakes
- ✗Returning
0in the base case instead of1, zeroing the whole product - ✗Computing in
intso the product overflows long beforelongwould - ✗Assuming
longcannot overflow —21!already does, silently withoutchecked
Follow-up questions
- →At what
ndoesFactorialoverflowlong, and how wouldBigIntegerchange that? - →How would you rewrite this iteratively to avoid deep recursion?
MiddleCodeRareSwap two array elements without a temporary variable
Swap two array elements without a temporary variable
Use a tuple swap: (a[i], a[j]) = (a[j], a[i]). The right side is evaluated fully before either assignment, so both elements exchange safely — even when i == j, where it just rewrites the same value. It needs no temp and avoids the arithmetic/XOR tricks that zero the element on self-swap.
Common mistakes
- ✗Using XOR or add/subtract, which zero out the element when
i == j - ✗Believing arithmetic swap is safe — it can overflow
intfor large values - ✗Sneaking in two local copies, which is just a renamed temporary variable
Follow-up questions
- →Exactly why does the XOR swap zero the element when
i == j? - →How does the tuple swap evaluate the right-hand side before assigning?