Я бы использовал массив, а не хэш-карту. Если мы ограничены ascii, это всего лишь 256 записей; если мы используем Unicode, 64 КБ. В любом случае не невозможный размер. Кроме того, я не вижу, как вы могли бы улучшить свой подход. Я пытаюсь придумать какой-нибудь умный прием, чтобы сделать его более эффективным, но я не могу придумать какой-либо.
Мне кажется, что ответ почти всегда будет целым списком символов: все те, которые используются ноль раз.
Обновление
Это, вероятно, наиболее эффективный вариант в Java. Для удобства я предполагаю, что мы используем простую Ascii.
public List<Character> rarest(String s)
{
int[] freq=new int[256];
for (int p=s.length()-1;p>=0;--p)
{
char c=s.charAt(p);
if (c>255)
throw new UnexpectedDataException("Wasn't expecting that");
++freq[c];
}
int min=Integer.MAX_VALUE;
for (int x=freq.length-1;x>=0;--x)
{
// I'm assuming we don't want chars with frequency of zero
if (freq[x]>0 && min>freq[x])
min=freq[x];
}
List<Character> rares=new ArrayList<Character>();
for (int x=freq.length-1;x>=0;--x)
{
if (freq[x]==min)
rares.add((char)x);
}
return rares;
}
Любые усилия по сохранению списка, отсортированного по частоте, по мере продвижения будут гораздо более неэффективными, поскольку придется пересортировать каждый раз, когда вы проверяете один символ.
Любая попытка вообще отсортировать список частот будет более неэффективной, поскольку сортировка всего списка будет выполняться медленнее, чем просто выбор наименьшего значения.
Сортировка строки и последующий подсчет будут выполняться медленнее, поскольку сортировка будет стоить дороже, чем подсчет.
Технически было бы быстрее создать простой массив в конце, а не ArrayList, но ArrayList делает немного более читабельный код.
Может быть, есть способ сделать это быстрее, но я подозреваю, что это близко к оптимальному решению. Мне, конечно, было бы интересно узнать, есть ли у кого-нибудь идея получше.