Вопрос: задан массив целых чисел heights
, представляющих высоту столбца гистограммы, где ширина каждого столбца равна 1
, верните площадь самого большого прямоугольника на гистограмме.
Решение грубой силы.
для каждого бара, если мы найдем левую и правую границы прямоугольника, где текущий бар имеет минимальную высоту, мы можем вычислить площадь как
площадь = (правая[i]-левая[i]-1)*высота[i]
Пробный запуск с примером.
высоты = [2,1,5,6,2,3]
слева = [-1,0,1,2,1,4]
справа = [1,6,4,4,6,6]
площади = [(1-(-1)-1)*2, (6–0–1)*1, (4–1–1)*5, (4–2–1)*6, (6–1 –1)*2, (6–4–1)*3]
площади = [2, 5, 10, 6, 8, 3]
максимальная площадь = 10
Временная сложность O(N²)
Можем ли мы решить эту задачу за O(N)?
Что нам мешает с точки зрения временной сложности? Вложенный цикл while в строке № 8 и 15 в коде 1.
for(int i = 0; i < n; i++) { int leftBoundary = i-1; while(leftBoundary >= 0 && heights[leftBoundary] >= heights[i]){ leftBoundary--; } left[i] = leftBoundary; }
Посмотрите внимательно на этот кусок кода. Мы вычисляем значения слева направо, в основном, мы вычисляем значение слева [i-1] до левого [i].
if(height[i-1] ≥ height[i]), то левая граница для i по крайней мере равна левой границе i-1. Подумайте об этом, попытайтесь понять это на примере
Так что мы можем сделать это
for(int i = 0; i < n; i++) { int leftBoundary = i-1; while(leftBoundary >= 0 && heights[leftBoundary] >= heights[i]){ leftBoundary = left[leftBoundary]; } left[i] = leftBoundary; }
Какова временная сложность этого кода сейчас.
Мы не сканируем повторно каждый элемент слева, вместо этого мы повторно используем ранее рассчитанные левые границы. Это сделает временную сложность от O(N²) до O(N)
О(N) код.
Это крутое решение.
Есть еще один способ решить эту проблему, который также довольно интуитивно понятен, если вы хорошо разбираетесь в решении проблем, основанных на стеке.
Если мы будем поддерживать стек возрастающей высоты и всякий раз, когда мы сталкиваемся с высотой, которая меньше, чем высота на вершине стека, мы достигаем правой границы для верхнего элемента стека.
Давайте разберемся на примере
высоты = [2,1,5,6,2,3]
stack = [-1] // поддерживать только индекс
- i = 0
- стек = [-1,0] maxArea = 0 - i = 1 // heights[1] ‹ height[stack.top]
- top = stack.pop() =› 0
- r = i =› 1, l = stack.top =› -1
- area = (r-l-1)*height[top] =› (1-(-1)-1)*2 =› 2
- stack.push(i)
- стек=[-1,1] - i = 2
- stack=[-1,1,2] as height[i] › height[stack.top] - i = 3
- стек=[-1,1,2,3] - i = 4
- верх = 3; стек.поп(); stack=[-1,1,2]
- r = 4, l = stack.top =› 2
- area = (4–2–1)*6 =› 6
- все еще height[i] ‹ height[stack.top] =› 2 ‹ 5
- top = 2; stack = [-1,1]
- r = 4, l = 1
- area = (4–1–1)*height[top] =› 2 * 5 =› 10
Код
Также см.:
Удачного кодирования!!!