Поиск элемента в частично отсортированном массиве
У меня был следующий вопрос интервью.
Существует массив элементов nxn. Массив частично отсортирован. Самый большой элемент в строке i
меньше самого маленького элемента в строке i+1
.
Как вы можете найти данный элемент со сложностью O (n)
Вот мой пример:
Вы должны пойти в строку n/2. И начать сравнивать, например, вы ищете 100, а первое число, которое вы видите, равно 110, чтобы вы знали это либо в этой строке, либо в строках выше, теперь вы идете n/4 и так на.
Из комментариев
Разве это не O (n * log n)? У него есть разобрать все строки, которые он достигает двоичного поиска, поэтому число линейных поисков умноженное на количество строк, которые он придется сканировать в среднем. - Мартин Матисяк 5 минут назад.
Я не уверен, что это правильное решение. У кого-нибудь есть что-то лучше
Ответы
Ответ 1
Ваше решение действительно принимает O(n log n)
, предполагая, что вы ищете каждую строку, которую вы разбираете. Если вы не выполняете поиск по каждой строке, вы не можете точно выполнить двоичный шаг.
O(n)
решение:
Выберите строку n/2
, вместо того чтобы искать всю строку, мы просто берем первый элемент предыдущей строки и первый элемент следующей строки. O(1)
.
Мы знаем, что все элементы строки n/2
должны быть между этими выбранными значениями (это ключевое наблюдение). Если наше целевое значение лежит в интервале, то выполните поиск по всем трем строкам (3*O(n) = O(n)
).
Если наше значение находится за пределами этого диапазона, то продолжайте в режиме двоичного поиска, выбрав n/4
, если наше значение было меньше диапазона и 3n/4
row, если значение было больше, и снова сравнивалось с одним элементом смежные строки.
Поиск правильного блока из 3 строк будет стоить O(1) * O(log n)
, и поиск элемента будет стоить O(n)
.
Всего O(log n) + O(n) = O(n)
.
Ответ 2
Вот простая реализация - так как нам нужно O (n) для нахождения элемента внутри строки, я оставил bin-search...
void search(int n[][], int el) {
int minrow = 0, maxrow;
while (minrow < n.length && el >= n[minrow][0])
++minrow;
minrow = Math.max(0, minrow - 1);
maxrow = Math.min(n.length - 1, minrow + 1);
for (int row = minrow; row <= maxrow; ++row) {
for (int col = 0; col < n[row].length; ++col) {
if (n[row][col] == el) {
System.out.printf("found at %d,%d\n", row, col);
}
}
}
}