Поиск элемента в частично отсортированном массиве

У меня был следующий вопрос интервью.

Существует массив элементов 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);
            }
        }
    }
}