Прежде всего, я даю понять, что это задание, и я не ожидаю полных закодированных ответов. Все, что я ищу, это советы и, возможно, фрагменты кода, которые мне помогают.
Итак, я читаю около 900 000 слов, которые хранятся в массиве. Мне нужно подсчитывать уникальные слова, используя отсортированный массив (или arraylist) в java.
До сих пор я просто перебираю данный массив и использую
Collections.sort(words);
и Collections.binarySearch(words, wordToLook);
для достижения его следующего:
OrderedSet set = new OrderedSet();
for(String a : words){
if(!set.contains(a)){
set.add(a);
}
}
а также
public boolean contains(String word) {
Collections.sort(uniqueWords);
int result = Collections.binarySearch(uniqueWords, word);
if(result<0){
return false;
}else{
return true;
}
}
Этот код имеет время работы около 60 секунд, но мне было интересно, есть ли какой-нибудь лучший способ сделать это, потому что запуск сортировки каждый раз, когда добавляется элемент, кажется очень неэффективным (но couse необходим, если я должен использовать бинарный поиск).
Будем очень благодарны за любую обратную связь. Благодарю.
Таким образом, вы должны использовать отсортированный массив. Это нормально, поскольку вы (еще не) программируете в реальном мире.
Я предлагаю две альтернативы:
Первый использует двоичный поиск (который вы используете в своем текущем коде).
Я бы создал класс, который содержит два поля: слово (строка) и счетчик для этого слова (int). Вы построите отсортированный массив этих классов.
Начните с пустого массива и добавьте его, когда будете читать каждое слово. Для каждого слова выполните двоичный поиск слова в массиве, который вы строите. Поиск будет либо найти запись, содержащую слово (и вы увеличите счетчик), либо вы определите, что слово еще не находится в массиве.
Когда ваш двоичный поиск заканчивается, не найдя слово, вы создадите новый объект для хранения слова + count и добавьте его в массив в том месте, где закончился ваш поиск (будьте осторожны, чтобы убедиться, что ваша логика действительно делает это правильно чтобы сохранить сортировку списка). Конечно, для ваших слов установлено значение 1.
Другая альтернатива:
Прочитайте все свои слова в списке и отсортируйте его. После сортировки все дубликаты будут рядом друг с другом в списке.
Вы пройдете по этому отсортированному списку один раз и создадите список слов + count, когда идете. Если следующее слово, которое вы видите, совпадает с последним словом + count, увеличивайте счет. Если это новое слово, добавьте новое слово + счет в список результатов с count = 1.
Вы всегда можете использовать компаратор для получения уникальных значений.
List newList = new ArrayList(new Comparator() {
@Override
public int compare(words o1, words o2) {
if(o1.equalsIgnoreCase(o2)){
return 0;
}
return 1;
}
});
Теперь посчитайте:
words - newList = no. повторяющихся значений.
Надеюсь это поможет!!!!
Я бы не использовал отсортированный массив. Я бы создал Map<String, Integer>
где ключ является вашим словом, а значение - числом числа вхождений слова. Когда вы читаете каждое слово, сделайте что-то вроде этого:
Integer count = map.get(word);
if (count == null) {
count = 0;
}
map.put(word, count + 1);
Затем просто перейдите по набору записей карты и сделайте все, что вам нужно для подсчета.
Если вы знаете или можете оценить количество уникальных слов, вы должны использовать этот номер в конструкторе HashMap (так что вы не разрастаете карту много раз).
Если вы используете отсортированный массив, время выполнения не может быть больше, чем пропорционально NlogN (где N - количество слов в вашем списке). Если вы используете HashMap, вы можете достичь времени выполнения, которое линейно растет с помощью N (вы сохраняете коэффициент logN).
Еще одно преимущество использования карты - используемая память пропорциональна количеству уникальных слов, а не полному количеству слов (при условии, что вы строите карту при чтении слов, вместо того, чтобы читать все слова в коллекции, а затем добавлять их к карте).
public static int countUnique(array) {
if(array.length == 0) return 0;
int count = 1;
for i from 1 to array.length - 1 {
if(!array[i].equals(array[i - 1])) count++;
}
return count;
}
Это алгоритм O(N)
в псевдокоде для подсчета количества уникальных записей в отсортированном массиве. Идея заключается в том, что мы подсчитываем количество переходов между группами равных элементов. Тогда число уникальных записей - это число переходов плюс один (для первой записи).
Надеемся, вы увидите, как применить этот алгоритм к вашему массиву после сортировки элементов.