Znajdź minimum i maksimum — Zadanie rekrutacyjne #6

Czego szuka rekruter: obsługa pustej kolekcji, LINQ vs manual, czytelność
Poziom: Junior
Zadanie
Napisz funkcję, która w tablicy liczb całkowitych znajdzie najmniejszą i największą wartość. Nie używaj Math.Min/Math.Max ani LINQ (chyba że jako alternatywę).
Czego szuka rekruter
To zadanie o walidacji wejścia i wzorcu zwracania wyników. Rekruter patrzy na:
- Co się stanie dla pustej tablicy lub
null - Jak kandydat zwraca dwa wyniki — tuple, out parametry, osobna klasa
- Czy inicjalizuje
min/maxpoprawnie (pułapka: inicjalizacja zerem!)
Najczęstszy błąd: int min = 0, max = 0 — dla tablicy [-5, -3, -1] zwróci max = 0, co jest błędem bo 0 nie ma w tablicy.
Edge cases
- Pusta tablica — nie ma min/max, trzeba zgłosić błąd lub zwrócić
null - Tablica z jednym elementem — min = max = ten element
- Wszystkie elementy ujemne — min/max muszą być ujemne
- Tablica:
[int.MinValue, int.MaxValue]
❌ Częsty błąd — inicjalizacja zerem
// BŁĄD:
static (int min, int max) FindMinMax(int[] arr)
{
int min = 0, max = 0; // ← BŁĄD: dla [-5, -3, -1] zwróci max=0
foreach (var n in arr)
{
if (n < min) min = n;
if (n > max) max = n;
}
return (min, max);
}
✅ Poprawne rozwiązanie
static (int Min, int Max) FindMinMax(int[] arr)
{
if (arr == null || arr.Length == 0)
throw new ArgumentException("Tablica nie może być pusta.", nameof(arr));
int min = arr[0];
int max = arr[0];
for (int i = 1; i < arr.Length; i++)
{
if (arr[i] < min) min = arr[i];
if (arr[i] > max) max = arr[i];
}
return (min, max);
}
// Użycie:
var (min, max) = FindMinMax(new[] { 5, 2, 8, 1, 9, 3 });
Console.WriteLine($"Min: {min}, Max: {max}"); // Min: 1, Max: 9
Inicjalizacja min = max = arr[0] jest kluczowa — zaczynamy od pierwszego elementu jako punktu odniesienia.
Alternatywa — LINQ (jedna linia, ale dwa przejścia)
static (int Min, int Max) FindMinMaxLinq(int[] arr)
{
if (arr == null || arr.Length == 0)
throw new ArgumentException("Tablica nie może być pusta.");
return (arr.Min(), arr.Max());
}
Wadą jest podwójne przejście przez tablicę. Dla dużych danych lepsze jest jedno przejście z ręcznym porównaniem.
Wersja zwracająca null zamiast rzucania wyjątku
static (int Min, int Max)? TryFindMinMax(int[] arr)
{
if (arr == null || arr.Length == 0)
return null;
int min = arr[0], max = arr[0];
for (int i = 1; i < arr.Length; i++)
{
if (arr[i] < min) min = arr[i];
if (arr[i] > max) max = arr[i];
}
return (min, max);
}
Testy jednostkowe
[Fact]
public void FindMinMax_TypicalArray_ReturnsCorrectResult()
{
var (min, max) = FindMinMax(new[] { 5, 2, 8, 1, 9, 3 });
Assert.Equal(1, min);
Assert.Equal(9, max);
}
[Fact]
public void FindMinMax_AllNegative_ReturnsCorrectResult()
{
var (min, max) = FindMinMax(new[] { -5, -3, -10, -1 });
Assert.Equal(-10, min);
Assert.Equal(-1, max);
}
[Fact]
public void FindMinMax_SingleElement_ReturnsSameForBoth()
{
var (min, max) = FindMinMax(new[] { 42 });
Assert.Equal(42, min);
Assert.Equal(42, max);
}
[Fact]
public void FindMinMax_EmptyArray_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => FindMinMax(Array.Empty<int>()));
}
Co powiedzieć na rozmowie
“Inicjalizuję min i max pierwszym elementem tablicy, nie zerem — gdybym użył zera, dla tablic z samymi wartościami ujemnymi zwróciłbym nieprawidłowy wynik. Dla pustej tablicy rzucam ArgumentException bo min/max z pustego zbioru jest matematycznie nieokreślone.”
Podsumowanie
Kluczowe: inicjalizacja pierwszym elementem tablicy, nie 0. Edge case pustej tablicy to obowiązek. LINQ jest wygodny ale przechodzi tablicę dwukrotnie — warto o tym wspomnieć.
1 comment
Dodaj komentarz
Musisz się zalogować, aby móc dodać komentarz.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →
Cześć,
bardzo fajny wpis