Coding interviews
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
int[] data = { 10, 20, 30 };
Console.WriteLine(string.Join(",", Slice(data, 1, 2)));
int checks = 0;
void Check(bool value) { if (!value) throw new Exception("slice check"); checks++; }
Check(Slice(data, 3, 0).Length == 0); Check(Slice(Array.Empty<int>(), 0, 0).Length == 0);
foreach (var pair in new[] { (-1, 1), (0, -1), (2, 2), (int.MaxValue, 1) }) {
bool rejected = false; try { Slice(data, pair.Item1, pair.Item2); } catch (ArgumentOutOfRangeException) { rejected = true; } Check(rejected);
}
Console.WriteLine("boundary checks:" + checks);
static int[] Slice(int[] data, int start, int count) {
if (start < 0 || count < 0 || start > data.Length || count > data.Length - start) throw new ArgumentOutOfRangeException();
return data.AsSpan(start, count).ToArray();
}
Reveal answer and reasoning
The output lines, in order, are “20,30”; “boundary checks:6”. Start one and count two select twenty and thirty. The harness then checks an empty suffix, an empty source and four rejected numeric pairs, yielding six boundary checks. In particular, int.MaxValue is rejected before subtracting it from the length. No start-plus-count expression can wrap and make an invalid range appear valid.
Short-circuit evaluation rejects negative starts and starts beyond the length before evaluating the final difference. The empty end slice is intentional, not a loophole. The six counted checks exclude the initial displayed copy, so the final line is a check count rather than the length of the sliced data.
Validation is constant-time. Copying count elements takes O(count) time and O(count) result storage. Returning a span instead would change lifetime and aliasing constraints, while returning an array makes ownership simple. Auxiliary state is constant beyond the required copy; the input remains unchanged. Using start + count <= length without addressing overflow is not equivalent for arbitrary integer arguments. Off-by-one errors also appear when callers confuse count with an inclusive final index.
Null handling must be made explicit if this helper becomes a public API rather than relying on a later accidental exception.
What a strong answer covers
- Exact output: 20,30 | boundary checks:6
- Start one and count two select twenty and thirty.
- Using start + count <= length without addressing overflow is not equivalent for arbitrary integer arguments.
Common pitfall
Using start + count <= length without addressing overflow is not equivalent for arbitrary integer arguments. Off-by-one errors also appear when callers confuse count with an inclusive final index. Null handling must be made explicit if this helper becomes a public API rather than relying on a later accidental exception.
Follow-up questions
- Add start equal to length with count one, and start zero with count equal to length. Hint: one crosses the exclusive end and one copies the entire array. Verify that changing the returned array does not mutate the source.
- How would the ownership claim change for an array whose elements are mutable reference objects?
Self-review
Choose what to revisit. These marks are your own assessment and are separate from lesson completion.