Skip to content

Commit 5a37bed

Browse files
authored
Update 0084.柱状图中最大的矩形.md
补全所有python解法,补充comment
1 parent 33768a0 commit 5a37bed

File tree

1 file changed

+119
-34
lines changed

1 file changed

+119
-34
lines changed

problems/0084.柱状图中最大的矩形.md

Lines changed: 119 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -281,52 +281,137 @@ class Solution {
281281

282282
Python:
283283

284-
动态规划
285284
```python3
285+
286+
# 双指针;暴力解法(leetcode超时)
286287
class Solution:
287288
def largestRectangleArea(self, heights: List[int]) -> int:
289+
# 从左向右遍历:以每一根柱子为主心骨(当前轮最高的参照物),迭代直到找到左侧和右侧各第一个矮一级的柱子
290+
res = 0
291+
292+
for i in range(len(heights)):
293+
left = i
294+
right = i
295+
# 向左侧遍历:寻找第一个矮一级的柱子
296+
for _ in range(left, -1, -1):
297+
if heights[left] < heights[i]:
298+
break
299+
left -= 1
300+
# 向右侧遍历:寻找第一个矮一级的柱子
301+
for _ in range(right, len(heights)):
302+
if heights[right] < heights[i]:
303+
break
304+
right += 1
305+
306+
width = right - left - 1
307+
height = heights[i]
308+
res = max(res, width * height)
309+
310+
return res
311+
312+
# DP动态规划
313+
class Solution:
314+
def largestRectangleArea(self, heights: List[int]) -> int:
315+
size = len(heights)
316+
# 两个DP数列储存的均是下标index
317+
min_left_index = [0] * size
318+
min_right_index = [0] * size
288319
result = 0
289-
minleftindex, minrightindex = [0]*len(heights), [0]*len(heights)
320+
321+
# 记录每个柱子的左侧第一个矮一级的柱子的下标
322+
min_left_index[0] = -1 # 初始化防止while死循环
323+
for i in range(1, size):
324+
# 以当前柱子为主心骨,向左迭代寻找次级柱子
325+
temp = i - 1
326+
while temp >= 0 and heights[temp] >= heights[i]:
327+
# 当左侧的柱子持续较高时,尝试这个高柱子自己的次级柱子(DP
328+
temp = min_left_index[temp]
329+
# 当找到左侧矮一级的目标柱子时
330+
min_left_index[i] = temp
290331

291-
minleftindex[0]=-1
292-
for i in range(1,len(heights)):
293-
t = i-1
294-
while t>=0 and heights[t]>=heights[i]: t=minleftindex[t]
295-
minleftindex[i]=t
296-
297-
minrightindex[-1]=len(heights)
298-
for i in range(len(heights)-2,-1,-1):
299-
t=i+1
300-
while t<len(heights) and heights[t]>=heights[i]: t=minrightindex[t]
301-
minrightindex[i]=t
332+
# 记录每个柱子的右侧第一个矮一级的柱子的下标
333+
min_right_index[size-1] = size # 初始化防止while死循环
334+
for i in range(size-2, -1, -1):
335+
# 以当前柱子为主心骨,向右迭代寻找次级柱子
336+
temp = i + 1
337+
while temp < size and heights[temp] >= heights[i]:
338+
# 当右侧的柱子持续较高时,尝试这个高柱子自己的次级柱子(DP
339+
temp = min_right_index[temp]
340+
# 当找到右侧矮一级的目标柱子时
341+
min_right_index[i] = temp
342+
343+
for i in range(size):
344+
area = heights[i] * (min_right_index[i] - min_left_index[i] - 1)
345+
result = max(area, result)
302346

303-
for i in range(0,len(heights)):
304-
left = minleftindex[i]
305-
right = minrightindex[i]
306-
summ = (right-left-1)*heights[i]
307-
result = max(result,summ)
308347
return result
309-
```
310-
单调栈 版本二
311-
```python3
348+
349+
# 单调栈
312350
class Solution:
313351
def largestRectangleArea(self, heights: List[int]) -> int:
314-
heights.insert(0,0) # 数组头部加入元素0
315-
heights.append(0) # 数组尾部加入元素0
316-
st = [0]
352+
# Monotonic Stack
353+
'''
354+
找每个柱子左右侧的第一个高度值小于该柱子的柱子
355+
单调栈:栈顶到栈底:从大到小(每插入一个新的小数值时,都要弹出先前的大数值)
356+
栈顶,栈顶的下一个元素,即将入栈的元素:这三个元素组成了最大面积的高度和宽度
357+
情况一:当前遍历的元素heights[i]大于栈顶元素的情况
358+
情况二:当前遍历的元素heights[i]等于栈顶元素的情况
359+
情况三:当前遍历的元素heights[i]小于栈顶元素的情况
360+
'''
361+
362+
# 输入数组首尾各补上一个0(与42.接雨水不同的是,本题原首尾的两个柱子可以作为核心柱进行最大面积尝试
363+
heights.insert(0, 0)
364+
heights.append(0)
365+
stack = [0]
317366
result = 0
318-
for i in range(1,len(heights)):
319-
while st!=[] and heights[i]<heights[st[-1]]:
320-
midh = heights[st[-1]]
321-
st.pop()
322-
if st!=[]:
323-
minrightindex = i
324-
minleftindex = st[-1]
325-
summ = (minrightindex-minleftindex-1)*midh
326-
result = max(summ,result)
327-
st.append(i)
367+
for i in range(1, len(heights)):
368+
# 情况一
369+
if heights[i] > heights[stack[-1]]:
370+
stack.append(i)
371+
# 情况二
372+
elif heights[i] == heights[stack[-1]]:
373+
stack.pop()
374+
stack.append(i)
375+
# 情况三
376+
else:
377+
# 抛出所有较高的柱子
378+
while stack and heights[i] < heights[stack[-1]]:
379+
# 栈顶就是中间的柱子,主心骨
380+
mid_index = stack[-1]
381+
stack.pop()
382+
if stack:
383+
left_index = stack[-1]
384+
right_index = i
385+
width = right_index - left_index - 1
386+
height = heights[mid_index]
387+
result = max(result, width * height)
388+
stack.append(i)
328389
return result
390+
391+
# 单调栈精简
392+
class Solution:
393+
def largestRectangleArea(self, heights: List[int]) -> int:
394+
heights.insert(0, 0)
395+
heights.append(0)
396+
stack = [0]
397+
result = 0
398+
for i in range(1, len(heights)):
399+
while stack and heights[i] < heights[stack[-1]]:
400+
mid_height = heights[stack[-1]]
401+
stack.pop()
402+
if stack:
403+
# area = width * height
404+
area = (i - stack[-1] - 1) * mid_height
405+
result = max(area, result)
406+
stack.append(i)
407+
return result
408+
409+
410+
411+
412+
329413
```
414+
*****
330415

331416
JavaScript:
332417
```javascript

0 commit comments

Comments
 (0)