Ответ 1
Да, это можно сделать лучше.
Прежде всего, подумайте о структуре данных, которая позволяет нам
- Обновить любое одно значение базового массива 1D в
O(logn)
время - Найдите сумму максимального подмассива массива в
O(1)
времени
Собственно, сбалансированное двоичное дерево, которое выглядит как ниже, может выполнять эту работу. Древовидную структуру можно описать как:
- Каждый лист node дерева представляет каждый элемент массива.
- Если внутренний node охватывает диапазон
[a, b]
, его левый дочерний элемент охватывает диапазон[a, c]
, а его правый дочерний элемент охватывает диапазон[c + 1, b]
, гдеc = floor((a + b) / 2))
. -
Корень node охватывает диапазон
[1, n]
.O / \ / \ / \ / \ / \ O O / \ / \ / \ / \ / \ / \ O O O O / \ / \ / \ / \ o o o o o o o o A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8]
К каждому node v
(включая листовые узлы и внутренние узлы) прикрепляются 4 поля:
-
S[v]
: сумма всех значений в диапазонеv
-
M[v]
: максимальная сумма субарама в диапазонеv
-
L[v]
: сумма максимального подмассива, начинающаяся с левой стороны диапазонаv
-
R[v]
: сумма максимального субарама, которая заканчивается в правой части диапазонаv
На основе приведенных выше определений мы можем найти следующие правила обновления:
- Для любого листа node
v
,S[v] = A[v]
,M[v] = L[v] = R[v] = max{0, A[v]}
- Для любого внутреннего node
v
и его дочерних элементовl
иr
,-
S[v] = S[l] + S[r]
-
M[v] = max{M[l], M[r], R[l] + L[r]}
-
L[v] = max{L[l], L[r] + S[l]}
-
R[v] = max{R[r], R[l] + S[r]}
-
Наконец, мы можем реализовать операции, упомянутые в начале.
- Чтобы обновить
A[i]
, мы можем найти соответствующий лист node в дереве и обновить поля по пути к корню, используя приведенные выше правила. - Максимальная сумма субарама просто
M[root]
.
Теперь обсудим, как найти максимальный прямоугольник, используя эту структуру данных. Если мы зафиксируем верхнюю строку и нижнюю строку прямоугольника на i
th и j
-й строки, проблема превратится в проблему с 1D максимальным суммарным суммированием, где A[k] = sum{B[i..j, k]}
. Ключевое понимание заключается в том, что при фиксированном i
, если мы перечислим j
в порядке возрастания, мы можем использовать приведенную выше структуру данных для поддержки базового массива 1D и быстрого поиска ответа. Псевдокод описывает идею:
result = 0
for i in (1, 2, ..., n)
set all fields of the binary tree T to 0
for j in (i, i + 1, ..., n)
for any k where B[j, k] != 0
T.update(k, A[k] + B[j, k])
result = max{M[root], result}
return result
Предположим, что матрица содержит m
ненулевые элементы, временная сложность этого алгоритма O(mn logn)
. В вашем случае m = O(n)
, поэтому временная сложность O(n^2 logn)
и лучше, чем O(n^3)
.