#java
#java
Вопрос:
Для простоты предположим, что у меня есть два набора слов, отсортированных в алфавитном порядке. Один набор начинается с «aardvark» и заканчивается на «melon», а другой начинается с «melon» и заканчивается на «zebra». Слово «дыня» появляется в обоих наборах.
Если бы я взял входное слово, скажем, «банан», что было бы хорошим (и эффективным) способом определить, к какому набору слов оно должно принадлежать? Примечание: это не вопрос о том, существует ли слово «банан» уже в одном наборе, а скорее вопрос о том, как определить, в каком наборе должно существовать слово.
Если есть алгоритм, который кто-то знает, отлично. Если они могут предоставить некоторую версию на Java, еще лучше!
Редактировать: следует также указать, что, хотя в моем примере всего 2 набора, я хочу, чтобы алгоритм работал с n наборами.
Комментарии:
1. должно существовать в зависимости от чего? категория?
2. В вашем примере
"melon"
(или любое другое слово) всегда является последним элементом в первом наборе? Если это так, это так же просто, как проверить, идет ли wordw
перед последним элементом первого набора (который"melon"
в вашем случае). Предполагая, что вы имеете в виду в отсортированном порядке. Обобщая, вам просто нужно проверить каждый набор, чтобы увидеть, идет ли это слово перед последним элементом в наборе, а затем определить, находится ли оно перед или после первого элемента. Если оно не встречается раньше, оно принадлежит этому набору.3. @GarrettHall — Нет, на основе алфавитного порядка.
4. @birryree — Да, melon всегда является последним словом. Однако для простоты у меня есть только 2 набора. Я хочу знать алгоритм для n числа наборов.
Ответ №1:
Для двух наборов:
Если word
это ваше слово (например "banana"
):
int cmp = word.compareTo("melon");
if (cmp < 0) {
// it belongs to the first set
} else if (cmp > 0) {
// it belongs to the second set
} else {
// the word is "melon"
}
Для n
наборов:
Поместите разделительные слова в ArrayList<String>
(назовите это dividers
) в алфавитном порядке:
ArrayList<String> dividers = new ArrayList<String>();
//... populate `dividers` ...
Collections.sort(dividers);
Теперь вы можете использовать Collections.binarySearch()
его, чтобы выяснить, к какому набору принадлежит это слово:
int pos = Collections.binarySearch(dividers, word);
if (pos >= 0) {
// the word is the divider between sets `pos` and `pos 1`
} else {
int num = -(pos 1);
// the word belong to set number `num`
}
(Здесь наборы нумеруются с нуля.)
Комментарии:
1. Хорошо, но что, если существует более 2 наборов? Извините, забыл добавить это к исходному вопросу. Я использовал только 2 набора для простоты, но в моей реальной программе будет много наборов, отсортированных в алфавитном порядке. Так, например: трубкозуб — яблоко, яблоко — банан, банан — преступление, преступление — собака, … и т. Д
2. @Rsaesha — что происходит, когда слово равно последнему слову в наборе?
3. @birryree — Если оно равно последнему слову в наборе, то должны быть возвращены как этот набор, так и набор после (если он существует).
Ответ №2:
Допустим, у вас есть n
наборы. Создайте список слов «раздела» в отсортированном порядке.
Тогда набор, к которому он принадлежит, просто:
List<String> partitions = Arrays.asList("melon", "strawberry");
int setIndex = -(Collections.binarySearch(partitions, "banana")) - 1;
Это работает, потому Collections.binarySearch
что возвращает позицию вставки (-1), если он не может найти ключ в списке. Если оно может столкнуться с одним из слов раздела, вам следует сначала проверить, является ли результат отрицательным.
Редактировать
Я отредактировал, чтобы убрать требование для значений «book-end» («трубкозуб» и «зебра»), поскольку они на самом деле только усложняют ситуацию.
Ответ №3:
Просто проверьте первую букву и посмотрите, находится ли она между (первой буквой набора 1) и (первой буквой последнего элемента набора 1). Если оно равно обеим первым буквам, переходите ко вторым буквам. Если оно не вписывается в этот набор, перейдите к следующему набору. Это BigO(n * m), где n — количество наборов, а m — количество букв во входном слове. Не так уж плохо, ИМО.
Ответ №4:
String mid = firstList.get(firstList.size()-1);
assert(mid.equals(secondList.get(0)));
if(newString.compareTo(mid) < 0) // belongs in first
else // belongs in second.
Очевидно, вам может потребоваться адаптировать некоторые вызовы методов в зависимости от того, как вы их выполняете.
Ответ №5:
Если вы используете двоичную кучу для хранения списков, то определение того, куда вставить слово, займет O (log n).
Ответ №6:
final int n = 99; // whatever
final SortedSet<String>[] allMySets = new SortedSet[ n ];
// put your sets into allMySets, no particular order required.
final String searchWord = "banana";
int i;
for ( i = 0; i < allMySets.length; i ) {
final SortedSet< String > ss = allMySets[i];
if ( searchWord.compareTo( ss.first() ) >= 0 amp;amp; searchWord.compareTo( ss.last() ) <= 0 ) {
System.out.println("Word " searchWord " belongs to set #" i);
break;
}
}
if ( i == allMySets.length ) {
System.out.println("No matching set found.");
// Maybe handle border case here...
}