Удалить один элемент, чтобы каждое число встречалось одинаковое количество раз
Наткнулся на задачу.
Дан массив длины n. Необходимо найти максимальное число l (2 <= l <= n), чтобы для префикса массива n длины l выполнялось условие - из него возможно удалить один элемент так, чтобы каждое число встречалось одинаковое число раз
Пара примеров для наглядности сути задачи:
В примерах в первой строчке подается размер массива. В следующей строке через пробел перечисляются элементы.
Пример 1
Ввод:
5
1 2 3 4 5
Вывод:
5
Пример 2
Ввод:
10
1 2 4 2 3 1 3 9 15 23
Вывод:
7
Изначально была мысль, что как будто надо с мапой это связать, но так ни к чему и не пришел...
Буду благодарен любым идеям, как это сделать оптимальным способом!
Ответы (1 шт):
Можно трекать количество повторяюцихся значений и, например, если все значения повторяются 1 раз или, например, все значения повторяются Х раз и какое то другое только один раз, то сохраняем длину префикса.
Код может выглядеть как то так
int GetMaxPrefix(int[] data)
{
var byNum = new Dictionary<int, int>();
var byRepCount = new Dictionary<int, int>();
var longest = 0;
for (int i = 0; i < data.Length; i++)
{
var item = data[i];
if (!byNum.ContainsKey(item)) byNum[item] = 1;
else byNum[item]++;
if (!byRepCount.ContainsKey(byNum[item])) byRepCount[byNum[item]] = 0;
if (!byRepCount.ContainsKey(byNum[item] - 1)) byRepCount[byNum[item] - 1] = 0;
byRepCount[byNum[item]]++;
byRepCount[byNum[item] - 1]--;
if (byRepCount[byNum[item] - 1] <= 0) byRepCount.Remove(byNum[item] - 1);
if (byRepCount.Count <= 2)
{
if (byRepCount.Count == 1 && byRepCount.ContainsKey(1)) longest = i;
if (byRepCount.Count == 2)
{
if (byRepCount.Values.Any(z => z == 1)) longest = i;
}
}
}
return longest + 1;
}
Проверка
Console.WriteLine(GetMaxPrefix(new [] {1, 2, 3, 4, 5}));
Console.WriteLine(GetMaxPrefix(new [] {1, 2, 4, 2, 3, 1, 3, 9, 15, 23}));
Вывод
5
7