Если это небольшие числа, то аллоцировать на стеке N+1 байт, где N это самое большое число, потом пройтись по искомому массиву и каждый раз когда встречается число M, то а аллоцированном массиве байт по сдвигу M инкрементить байт на 1 (и следить за переполнением, либо использовать по 2-4-8 байта на счетчик).
Потом пройтись по этим данным и узнать какое число сколько раз встретилось.
Пример на псевдокоде:
byte* buffer = stackalloc byte[maxNumber+1];
foreach(int number in numbersArray)
{
buffer[number]++; // может переполниться
}
for(var i = 0; i < maxNumber+1; i++)
{
var count = buffer[number];
if (count > 1)
{
Console.WriteLine($"Number {i} met {count} times");
}
}