Как мне найти номер в 2d массиве, отсортированном слева направо и сверху вниз?
Мне недавно дали этот вопрос интервью, и мне любопытно, каким было бы хорошее решение для этого.
Скажем, у меня есть 2d массив, где все числа в массиве расположены в порядке возрастания слева направо и сверху вниз.
Каков наилучший способ поиска и определения, находится ли целевое число в массиве?
Теперь мое первое желание - использовать бинарный поиск, так как мои данные отсортированы. Я могу определить, находится ли число в одной строке за O (log N) времени. Тем не менее, это 2 направления, которые сбивают меня с толку.
Другое решение, которое, как я думал, может сработать, - начать где-то посередине. Если среднее значение меньше, чем моя цель, то я могу быть уверен, что оно находится в левой квадратной части матрицы от середины. Затем я двигаюсь по диагонали и снова проверяю, уменьшая размер квадрата, в котором потенциально может находиться цель, пока я не отточу целевое число.
У кого-нибудь есть хорошие идеи по решению этой проблемы?
Пример массива:
Сортировка слева направо, сверху вниз.
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11
Ответы
Ответ 1
Здесь простой подход:
- Начните с нижнего левого угла.
- Если цель меньше этого значения, она должна быть выше нас, поэтому поднимитесь на одну.
- В противном случае мы знаем, что цель не может быть в этом столбце, поэтому двигайтесь вправо.
- Перейти к 2.
Для массива NxM
это выполняется в O(N+M)
. Я думаю, что это будет трудно сделать лучше. :)
Изменить: много хорошего обсуждения. Я говорил об общем случае выше; ясно, что если N
или M
малы, вы можете использовать подход бинарного поиска, чтобы сделать это во время, приближающемся к логарифмическому времени.
Вот некоторые подробности для любопытных:
история
Этот простой алгоритм называется " поиск в седле". Это было вокруг некоторое время, и это оптимально, когда N == M
Некоторые ссылки:
Однако, когда N < M
, интуиция предполагает, что бинарный поиск должен работать лучше, чем O(N+M)
: например, когда N == 1
, чистый бинарный поиск будет выполняться в логарифмическом, а не линейном времени.
В худшем случае
Ричард Берд исследовал эту интуицию о том, что бинарный поиск может улучшить алгоритм Saddleback в статье 2006 года:
Используя довольно необычный разговорный прием, Берд показывает нам, что для N <= M
эта задача имеет нижнюю границу Ω(N * log(M/N))
. Эта граница имеет смысл, поскольку она дает нам линейную производительность при N == M
и логарифмическую производительность при N == 1
.
Алгоритмы для прямоугольных массивов
Один из подходов, использующий построчный бинарный поиск, выглядит следующим образом:
- Начните с прямоугольного массива, где
N < M
. Допустим, N
- строки, а M
- столбцы. - Выполните бинарный поиск в средней строке
value
. Если мы найдем это, мы сделали. - В противном случае мы нашли соседнюю пару чисел
s
и g
, где s < value < g
. - Прямоугольник чисел над и слева от
s
меньше value
, поэтому мы можем его устранить. - Прямоугольник ниже и справа от
g
больше value
, поэтому мы можем его устранить. - Перейдите к шагу (2) для каждого из двух оставшихся прямоугольников.
С точки зрения сложности наихудшего случая, этот алгоритм делает log(M)
работу, чтобы устранить половину возможных решений, а затем рекурсивно вызывает себя дважды для двух меньших проблем. Нам нужно повторить меньшую версию этого log(M)
для каждой строки, но если количество строк мало по сравнению с количеством столбцов, то возможность удаления всех этих столбцов за логарифмическое время начинает приобретать смысл,
Это придает алгоритму сложность T(N,M) = log(M) + 2 * T(M/2, N/2)
, который, как показывает Бёрд, равен O(N * log(M/N))
.
Другой подход, опубликованный Крейгом Гидни, описывает алгоритм, аналогичный описанному выше: он проверяет строку за раз, используя размер шага M/N
Его анализ показывает, что это также приводит к производительности O(N * log(M/N))
.
Сравнение производительности
Анализ Big-O - это хорошо, но насколько хорошо эти подходы работают на практике? В приведенной ниже таблице рассматриваются четыре алгоритма для все более "квадратных" массивов:
![algorithm performance vs squareness]()
("Наивный" алгоритм просто ищет каждый элемент массива. "Рекурсивный" алгоритм описан выше. "Гибридный" алгоритм представляет собой реализацию алгоритма Гидни. Для каждого размера массива производительность измерялась путем синхронизации каждого алгоритма с фиксированным набором 1 000 000 случайно сгенерированных массивов.)
Некоторые заметные моменты:
- Как и ожидалось, алгоритмы "двоичного поиска" обеспечивают наилучшую производительность для прямоугольных массивов, а алгоритм Saddleback лучше всего работает для квадратных массивов.
- Алгоритм Saddleback работает хуже, чем "наивный" алгоритм для 1-мерных массивов, предположительно потому, что он выполняет множественные сравнения для каждого элемента.
- Падение производительности, которое алгоритмы "двоичного поиска" принимают для квадратных массивов, предположительно связано с накладными расходами на выполнение повторных двоичных поисков.
Резюме
Умное использование бинарного поиска может обеспечить производительность O(N * log(M/N)
как для прямоугольных, так и для квадратных массивов. Алгоритм O(N + M)
"обратная передача") намного проще, но страдает от снижения производительности, поскольку массивы становятся все более прямоугольными,
Ответ 2
Эта проблема занимает время Θ(b lg(t))
, где b = min(w,h)
и t=b/max(w,h)
. Я обсуждаю решение в этом сообщении в блоге.
Нижняя граница
Противник может заставить алгоритм делать запросы Ω(b lg(t))
, ограничиваясь главной диагональю:
![Adversary using main diagonal]()
Легенда: белые ячейки - это меньшие предметы, серые ячейки - более крупные предметы, желтые ячейки - предметы с меньшим или равным, а оранжевые - больше или равно. Противник заставляет решение быть в зависимости от того, какая желтая или оранжевая ячейка выполняет запросы алгоритма.
Обратите внимание, что существуют b
независимые отсортированные списки размера t
, требующие от Ω(b lg(t))
запросов полностью исключить.
Алгоритм
- (не ограничивая общности, считаем, что
w >= h
)
- Сравните целевой объект с ячейкой
t
слева от верхнего правого угла допустимой области
- Если элемент ячейки соответствует, верните текущую позицию.
- Если элемент ячейки меньше целевого элемента, удалите оставшиеся ячейки
t
в строке с бинарным поиском. Если соответствующий элемент найден во время выполнения этого, верните его позицию.
- В противном случае элемент ячейки больше целевого элемента, исключая короткие столбцы
t
.
- Если нет допустимой области, возвратите отказ
- Перейти к шагу 2
Поиск элемента:
![Finding an item]()
Определение элемента не существует:
![Determining an item doesn't exist]()
Легенда: белые ячейки - это меньшие элементы, серые ячейки - более крупные предметы, а зеленая ячейка - равный элемент.
Анализ
Есть короткие столбцы b*t
для устранения. Для устранения существует b
длинные строки. Устранение длинной строки стоит O(lg(t))
времени. Устранение коротких столбцов t
стоит O(1)
времени.
В худшем случае нам придется удалять каждый столбец и каждую строку, принимая время O(lg(t)*b + b*t*1/t) = O(b lg(t))
.
Обратите внимание, что я принимаю lg
зажима для результата выше 1 (т.е. lg(x) = log_2(max(2,x))
). Поэтому, когда w=h
, что означает t=1
, мы получаем ожидаемую оценку O(b lg(1)) = O(b) = O(w+h)
.
код
public static Tuple<int, int> TryFindItemInSortedMatrix<T>(this IReadOnlyList<IReadOnlyList<T>> grid, T item, IComparer<T> comparer = null) {
if (grid == null) throw new ArgumentNullException("grid");
comparer = comparer ?? Comparer<T>.Default;
// check size
var width = grid.Count;
if (width == 0) return null;
var height = grid[0].Count;
if (height < width) {
var result = grid.LazyTranspose().TryFindItemInSortedMatrix(item, comparer);
if (result == null) return null;
return Tuple.Create(result.Item2, result.Item1);
}
// search
var minCol = 0;
var maxRow = height - 1;
var t = height / width;
while (minCol < width && maxRow >= 0) {
// query the item in the minimum column, t above the maximum row
var luckyRow = Math.Max(maxRow - t, 0);
var cmpItemVsLucky = comparer.Compare(item, grid[minCol][luckyRow]);
if (cmpItemVsLucky == 0) return Tuple.Create(minCol, luckyRow);
// did we eliminate t rows from the bottom?
if (cmpItemVsLucky < 0) {
maxRow = luckyRow - 1;
continue;
}
// we eliminated most of the current minimum column
// spend lg(t) time eliminating rest of column
var minRowInCol = luckyRow + 1;
var maxRowInCol = maxRow;
while (minRowInCol <= maxRowInCol) {
var mid = minRowInCol + (maxRowInCol - minRowInCol + 1) / 2;
var cmpItemVsMid = comparer.Compare(item, grid[minCol][mid]);
if (cmpItemVsMid == 0) return Tuple.Create(minCol, mid);
if (cmpItemVsMid > 0) {
minRowInCol = mid + 1;
} else {
maxRowInCol = mid - 1;
maxRow = mid - 1;
}
}
minCol += 1;
}
return null;
}
Ответ 3
Я бы использовал стратегию "разделяй и властвуй" для этой проблемы, аналогично тому, что вы предлагали, но детали немного отличаются.
Это будет рекурсивный поиск по поддиапазонам матрицы.
На каждом шаге выберите элемент в середине диапазона. Если найденное значение - это то, что вы ищете, то все готово.
В противном случае, если найденное значение меньше требуемого значения, то вы знаете, что оно находится не в квадранте выше и слева от вашей текущей позиции. Поэтому рекурсивно выполните поиск по двум поддиапазонам: все (исключительно) под текущей позицией и все (исключительно) вправо, которое находится над текущей позицией или над ней.
В противном случае (найденное значение больше требуемого значения), вы знаете, что он не находится в квадранте ниже и справа от вашей текущей позиции. Поэтому рекурсивно выполните поиск по двум поддиапазонам: все (исключительно) слева от текущей позиции и все (исключительно) над текущей позицией, находящейся в текущем столбце или столбце справа.
И ba-da-bing, вы его нашли.
Обратите внимание, что каждый рекурсивный вызов обрабатывает только текущий поддиапазон, а не (например) ВСЕ строки выше текущей позиции. Только те, которые находятся в текущем поддиапазоне.
Здесь для вас есть псевдокод:
bool numberSearch(int[][] arr, int value, int minX, int maxX, int minY, int maxY)
if (minX == maxX and minY == maxY and arr[minX,minY] != value)
return false
if (arr[minX,minY] > value) return false; // Early exits if the value can't be in
if (arr[maxX,maxY] < value) return false; // this subrange at all.
int nextX = (minX + maxX) / 2
int nextY = (minY + maxY) / 2
if (arr[nextX,nextY] == value)
{
print nextX,nextY
return true
}
else if (arr[nextX,nextY] < value)
{
if (numberSearch(arr, value, minX, maxX, nextY + 1, maxY))
return true
return numberSearch(arr, value, nextX + 1, maxX, minY, nextY)
}
else
{
if (numberSearch(arr, value, minX, nextX - 1, minY, maxY))
return true
reutrn numberSearch(arr, value, nextX, maxX, minY, nextY)
}
Ответ 4
Два основных ответа до сих пор кажутся возможно O(log N)
"ZigZag method" и O(N+M)
методом двоичного поиска. Я думал, что сделаю некоторое тестирование, сравнивая два метода с некоторыми различными настройками. Вот подробности:
В каждом тесте массив равен N x N, при этом N изменяется от 125 до 8000 (самая большая моя куча JVM может обрабатывать). Для каждого размера массива я выбрал случайное место в массиве, чтобы поместить один 2
. Затем я помещаю a 3
везде (справа и внизу 2), а затем заполнял остальную часть массива 1
. Некоторые из более ранних комментаторов, казалось, думали, что такой тип установки приведет к наихудшему времени выполнения обоих алгоритмов. Для каждого размера массива я выбрал 100 различных случайных местоположений для 2 (цель поиска) и прошел тест. Я записал среднее время запуска и наихудшее время выполнения для каждого алгоритма. Поскольку это происходило слишком быстро, чтобы получить хорошие показания MS на Java, и, поскольку я не доверяю Java nanoTime(), я каждый раз повторял каждый тест 1000 раз, чтобы постоянно добавлять равномерный коэффициент смещения. Вот результаты:
![enter image description here]()
ZigZag избивает бинарный файл в каждом тесте как в среднем, так и в худшем случае, однако все они находятся на порядок друг от друга более или менее.
Вот код Java:
public class SearchSortedArray2D {
static boolean findZigZag(int[][] a, int t) {
int i = 0;
int j = a.length - 1;
while (i <= a.length - 1 && j >= 0) {
if (a[i][j] == t) return true;
else if (a[i][j] < t) i++;
else j--;
}
return false;
}
static boolean findBinarySearch(int[][] a, int t) {
return findBinarySearch(a, t, 0, 0, a.length - 1, a.length - 1);
}
static boolean findBinarySearch(int[][] a, int t,
int r1, int c1, int r2, int c2) {
if (r1 > r2 || c1 > c2) return false;
if (r1 == r2 && c1 == c2 && a[r1][c1] != t) return false;
if (a[r1][c1] > t) return false;
if (a[r2][c2] < t) return false;
int rm = (r1 + r2) / 2;
int cm = (c1 + c2) / 2;
if (a[rm][cm] == t) return true;
else if (a[rm][cm] > t) {
boolean b1 = findBinarySearch(a, t, r1, c1, r2, cm - 1);
boolean b2 = findBinarySearch(a, t, r1, cm, rm - 1, c2);
return (b1 || b2);
} else {
boolean b1 = findBinarySearch(a, t, r1, cm + 1, rm, c2);
boolean b2 = findBinarySearch(a, t, rm + 1, c1, r2, c2);
return (b1 || b2);
}
}
static void randomizeArray(int[][] a, int N) {
int ri = (int) (Math.random() * N);
int rj = (int) (Math.random() * N);
a[ri][rj] = 2;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (i == ri && j == rj) continue;
else if (i > ri || j > rj) a[i][j] = 3;
else a[i][j] = 1;
}
}
}
public static void main(String[] args) {
int N = 8000;
int[][] a = new int[N][N];
int randoms = 100;
int repeats = 1000;
long start, end, duration;
long zigMin = Integer.MAX_VALUE, zigMax = Integer.MIN_VALUE;
long binMin = Integer.MAX_VALUE, binMax = Integer.MIN_VALUE;
long zigSum = 0, zigAvg;
long binSum = 0, binAvg;
for (int k = 0; k < randoms; k++) {
randomizeArray(a, N);
start = System.currentTimeMillis();
for (int i = 0; i < repeats; i++) findZigZag(a, 2);
end = System.currentTimeMillis();
duration = end - start;
zigSum += duration;
zigMin = Math.min(zigMin, duration);
zigMax = Math.max(zigMax, duration);
start = System.currentTimeMillis();
for (int i = 0; i < repeats; i++) findBinarySearch(a, 2);
end = System.currentTimeMillis();
duration = end - start;
binSum += duration;
binMin = Math.min(binMin, duration);
binMax = Math.max(binMax, duration);
}
zigAvg = zigSum / randoms;
binAvg = binSum / randoms;
System.out.println(findZigZag(a, 2) ?
"Found via zigzag method. " : "ERROR. ");
//System.out.println("min search time: " + zigMin + "ms");
System.out.println("max search time: " + zigMax + "ms");
System.out.println("avg search time: " + zigAvg + "ms");
System.out.println();
System.out.println(findBinarySearch(a, 2) ?
"Found via binary search method. " : "ERROR. ");
//System.out.println("min search time: " + binMin + "ms");
System.out.println("max search time: " + binMax + "ms");
System.out.println("avg search time: " + binAvg + "ms");
}
}
Ответ 5
Это краткое доказательство нижней оценки задачи.
Вы не можете сделать это лучше, чем линейное время (в терминах размеров массива, а не количества элементов). В приведенном ниже массиве каждый из элементов, обозначенных как *
, может быть либо 5, либо 6 (независимо от других). Поэтому, если ваше целевое значение равно 6 (или 5), алгоритм должен изучить все из них.
1 2 3 4 *
2 3 4 * 7
3 4 * 7 8
4 * 7 8 9
* 7 8 9 10
Конечно, это также расширяется до больших массивов. Это означает, что этот ответ является оптимальным.
Обновление: Как отметил Джеффри Л. Уитледж, он является оптимальным только как асимптотическая нижняя граница времени выполнения и размер входных данных (рассматривается как одна переменная). Время работы, рассматриваемое как функция с двумя переменными для обоих размеров массива, может быть улучшено.
Ответ 6
Я думаю Вот ответ, и он работает для любой сортированной матрицы
bool findNum(int arr[][ARR_MAX],int xmin, int xmax, int ymin,int ymax,int key)
{
if (xmin > xmax || ymin > ymax || xmax < xmin || ymax < ymin) return false;
if ((xmin == xmax) && (ymin == ymax) && (arr[xmin][ymin] != key)) return false;
if (arr[xmin][ymin] > key || arr[xmax][ymax] < key) return false;
if (arr[xmin][ymin] == key || arr[xmax][ymax] == key) return true;
int xnew = (xmin + xmax)/2;
int ynew = (ymin + ymax)/2;
if (arr[xnew][ynew] == key) return true;
if (arr[xnew][ynew] < key)
{
if (findNum(arr,xnew+1,xmax,ymin,ymax,key))
return true;
return (findNum(arr,xmin,xmax,ynew+1,ymax,key));
} else {
if (findNum(arr,xmin,xnew-1,ymin,ymax,key))
return true;
return (findNum(arr,xmin,xmax,ymin,ynew-1,key));
}
}
Ответ 7
Интересный вопрос. Рассмотрите эту идею - создайте одну границу, где все числа больше вашей цели, а другая, где все числа меньше вашей цели. Если что-то осталось между ними, это ваша цель.
Если я ищу 3 в вашем примере, я читаю через первую строку, пока не нажму 4, а затем найдите наименьшее соседнее число (включая диагонали) больше 3:
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11
Теперь я делаю то же самое для тех чисел, которые меньше 3:
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11
Теперь я спрашиваю, что-нибудь внутри двух границ? Если да, то это должно быть 3. Если нет, то нет 3. Сортировка косвенно, так как я фактически не нахожу номер, я просто выводю, что он должен быть там. У этого есть дополнительный бонус подсчета ВСЕХ 3-х.
Я попробовал это на некоторых примерах и, похоже, работает нормально.
Ответ 8
Бинарный поиск по диагонали массива является наилучшим вариантом.
Мы можем узнать, является ли элемент меньше или равен элементам в диагонали.
Ответ 9
а. Сделайте двоичный поиск на тех строках, где может быть установлен целевой номер.
В. Сделайте это графиком: найдите номер, взяв всегда самого маленького невидимого соседа node и отступая, когда найдено слишком большое число
Ответ 10
Бинарный поиск будет лучшим подходом, imo. Начиная с 1/2 x, 1/2 y сократит его пополам. IE 5x5-квадрат был бы чем-то вроде x == 2/y == 3. Я округлил одно значение вниз и одно значение до лучшей зоны в направлении целевого значения.
Для ясности следующая итерация даст вам что-то вроде x == 1/y == 2 OR x == 3/y == 5
Ответ 11
Итак, для начала предположим, что мы используем квадрат.
1 2 3
2 3 4
3 4 5
1. Поиск квадрата
Я бы использовал бинарный поиск по диагонали. Целью является определение меньшего числа, которое не строго ниже целевого числа.
Скажем, я ищу 4
, например, тогда я бы остановил поиск 5
в (2,2)
.
Тогда я уверен, что если 4
находится в таблице, он находится в позиции либо (x,2)
, либо (2,x)
с x
в [0,2]
. Ну, это всего 2 бинарных поиска.
Сложность не сложна: O(log(N))
(3 бинарных поиска в диапазонах длины N
)
2. Поиск прямоугольника, наивный подход
Конечно, это становится немного сложнее, когда N
и M
отличаются (прямоугольником), рассмотрим этот вырожденный случай:
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17
И скажем, что я ищу 9
... Диагональный подход по-прежнему хорош, но определение диагональных изменений. Здесь моя диагональ [1, (5 or 6), 17]
. Скажем, я взял [1,5,17]
, тогда я знаю, что если 9
находится в таблице, то он либо находится в подчасти:
5 6 7 8
6 7 8 9
10 11 12 13 14 15 16
Это дает нам 2 прямоугольника:
5 6 7 8 10 11 12 13 14 15 16
6 7 8 9
Итак, мы можем рекурсировать! вероятно, начиная с единицы с меньшим количеством элементов (хотя в этом случае она убивает нас).
Я должен указать, что если одно из измерений меньше 3
, мы не можем применять диагональные методы и должны использовать двоичный поиск. Здесь это означало бы:
- Применить двоичный поиск на
10 11 12 13 14 15 16
, не найден
- Применить двоичный поиск на
5 6 7 8
, не найден
- Применить двоичный поиск на
6 7 8 9
, не найден
Это сложно, потому что для достижения хорошей производительности вы можете различать несколько случаев, в зависимости от общей формы....
3. Поиск прямоугольника, жестокого подхода
Было бы намного проще, если бы мы имели дело с квадратом... так что пусть просто квадратные вещи.
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17
17 . . . . . . 17
. .
. .
. .
17 . . . . . . 17
Теперь мы имеем квадрат.
Конечно, мы, скорее всего, НЕ будем создавать эти строки, мы могли бы просто имитировать их.
def get(x,y):
if x < N and y < M: return table[x][y]
else: return table[N-1][M-1] # the max
поэтому он ведет себя как квадрат, не занимая больше памяти (за счет скорости, возможно, в зависимости от кеша... о хорошо: p)
Ответ 12
EDIT:
Я неправильно понял вопрос. Как отмечают в комментариях, это работает только в более ограниченном случае.
В языке, таком как C, который хранит данные в строчном порядке, просто рассматривайте его как 1D-массив размера n * m и используйте двоичный поиск.
Ответ 13
У меня есть рекурсивное решение Divide and Conquer.
Основная идея для одного шага: Мы знаем, что Left-Upper (LU) наименьший, а правый-нижний (RB) является наибольшим номером, поэтому заданное No (N) должно: N >= LU и N <= = RB
IF N == LU и N == RB:: Element Found и Abort возвращают позицию/индекс
Если N >= LU и N <= RB = FALSE, No не существует и прерывается.
Если N >= LU и N = RB = TRUE, разделите 2D-массив в 4 равных частях 2D-массива каждый логически. А затем примените один и тот же шаг к всем четырем поддиапазонам.
Мое Алго правильное Я реализовал на своем компьютере друзей.
Сложность: каждые 4 сравнения могут использоваться для вывода полного количества элементов на одну четвертую в худшем случае.
Итак, моя сложность составляет 1 + 4 x lg (n) + 4
Но действительно ожидал, что это будет работать над O (n)
Я думаю, что что-то не так где-то в моем вычислении Сложности, пожалуйста, исправьте, если так..
Ответ 14
public boolean searchSortedMatrix(int arr[][] , int key , int minX , int maxX , int minY , int maxY){
// base case for recursion
if(minX > maxX || minY > maxY)
return false ;
// early fails
// array not properly intialized
if(arr==null || arr.length==0)
return false ;
// arr[0][0]> key return false
if(arr[minX][minY]>key)
return false ;
// arr[maxX][maxY]<key return false
if(arr[maxX][maxY]<key)
return false ;
//int temp1 = minX ;
//int temp2 = minY ;
int midX = (minX+maxX)/2 ;
//if(temp1==midX){midX+=1 ;}
int midY = (minY+maxY)/2 ;
//if(temp2==midY){midY+=1 ;}
// arr[midX][midY] = key ? then value found
if(arr[midX][midY] == key)
return true ;
// alas ! i have to keep looking
// arr[midX][midY] < key ? search right quad and bottom matrix ;
if(arr[midX][midY] < key){
if( searchSortedMatrix(arr ,key , minX,maxX , midY+1 , maxY))
return true ;
// search bottom half of matrix
if( searchSortedMatrix(arr ,key , midX+1,maxX , minY , maxY))
return true ;
}
// arr[midX][midY] > key ? search left quad matrix ;
else {
return(searchSortedMatrix(arr , key , minX,midX-1,minY,midY-1));
}
return false ;
}
Ответ 15
Оптимальным решением является запуск в верхнем левом углу, который имеет минимальное значение. Двигайтесь по диагонали вниз вправо, пока не нажмете элемент, значение которого >= значение данного элемента. Если значение элемента равно значению для данного элемента, return будет найдено как true.
В противном случае мы можем действовать двумя способами.
Стратегия 1:
- Переместитесь в колонку и найдите данный элемент, пока мы не достигнем конца. Если найдено, возврат найден как истинный
- Двигайтесь влево в строке и ищите данный элемент, пока мы не достигнем конца. Если найдено, возврат найден как истинный
- return найден как false
Стратегия 2:
Обозначим через я индекс строки, а j - индекс столбца диагонального элемента, который мы остановили. (Здесь мы имеем я = j, BTW). Пусть k = 1.
- Повторите приведенные ниже шаги, пока i-k >= 0
- Искать, если [i-k] [j] равен данному элементу. если да, возврат найден как истинный.
- Искать, если [i] [j-k] равен данному элементу. если да, возврат найден как истинный.
- Приращение k
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11
Ответ 16
Я предлагаю хранить все символы в 2D list
. затем найдите индекс требуемого элемента, если он существует в списке.
Если нет, напечатайте соответствующее сообщение еще напечатать строку и столбец как:
row = (index/total_columns)
и column = (index%total_columns -1)
Это приведет к появлению только бинарного времени поиска в списке.
Пожалуйста, предложите любые исправления.:)
Ответ 17
Если O (M log (N)) решение одобрено для массива MxN -
template <size_t n>
struct MN * get(int a[][n], int k, int M, int N){
struct MN *result = new MN;
result->m = -1;
result->n = -1;
/* Do a binary search on each row since rows (and columns too) are sorted. */
for(int i = 0; i < M; i++){
int lo = 0; int hi = N - 1;
while(lo <= hi){
int mid = lo + (hi-lo)/2;
if(k < a[i][mid]) hi = mid - 1;
else if (k > a[i][mid]) lo = mid + 1;
else{
result->m = i;
result->n = mid;
return result;
}
}
}
return result;
}
Рабочая демонстрация С++.
Пожалуйста, дайте мне знать, если это не сработает или если есть ошибка.
Ответ 18
Учитывая квадратную матрицу следующим образом:
[ a b c ]
[ d e f ]
[ i j k ]
Мы знаем, что a < c, d < f, я < к. Мы не знаем, является ли d < c или d > c и т.д. У нас есть гарантии только в 1-мерном виде.
Глядя на конечные элементы (c, f, k), мы можем сделать какой-то фильтр: N < c? search(): next(). Таким образом, у нас есть n итераций по строкам, причем каждая строка принимает либо O (log (n)) для двоичного поиска, либо O (1), если отфильтрована.
Позвольте мне привести пример, где N = j,
1) Проверить строку 1. j < с? (нет, идите дальше)
2) Проверьте строку 2. j < е? (да, поиск в бинах ничего не получает)
3) Проверьте строку 3. j < к? (да, поиск в бине находит его)
Повторите попытку с помощью N = q,
1) Проверить строку 1. q < с? (нет, идите дальше)
2) Проверить строку 2. q < е? (нет, идите дальше)
3) Проверить строку 3. q < к? (нет, идите дальше)
Вероятно, есть лучшее решение, но это легко объяснить..:)
Ответ 19
Поскольку это вопрос интервью, это, по-видимому, приведет к обсуждению алгоритмов Параллельное программирование и Map-reduce.
См. http://code.google.com/intl/de/edu/parallel/mapreduce-tutorial.html