Ну, для начала давайте предположим, что мы используем квадрат.
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)