Leetcode Array
林老师让我们在 Leetcode 找一道标签为 Array 的题目,用 Python 写。我随便找了一个 Hard 的来看看。
我找了题目 #84 ,题目链接 https://leetcode.com/problems/largest-rectangle-in-histogram/description/ 。
题意是说,给定 a1,a2,⋯an a 1 , a 2 , ⋯ a n ,求 max1≤i≤j≤n(min{ai,ai+1,⋯,aj}∗(j−i+1)) m a x 1 ≤ i ≤ j ≤ n ( m i n { a i , a i + 1 , ⋯ , a j } ∗ ( j − i + 1 ) )
它没写数据范围,我就枚举 i,j i , j ,敲了个 O(n2) O ( n 2 ) 的暴力交上去了……
class Solution:
def largestRectangleArea(self, heights):
ans = 0
for i in range(0, len(heights)):
p = 10000000000000
for j in range(i, len(heights)):
if heights[j] < p:
p = heights[j]
if p * (j - i + 1) > ans:
ans = p * (j - i + 1)
return ans
果然TLE了……
好吧,我想想怎么优化一下……
想到啦!线段树!把 heights 从大到小排序,然后把该 heights 对应的点的编号插入到线段树中,然后求最大连续区间!复杂度可是 O(nlogn) O ( n log n ) 的呢!
class Solution:
def __init__(self):
self.h = []
self.lmx = []
self.rmx = []
self.mx = []
def add(self, p, left, right, x):
if left == right:
self.lmx[p] = 1
self.rmx[p] = 1
self.mx[p] = 1
return
mid = int((left + right) / 2)
if x <= mid:
self.add(p * 2, left, mid, x)
else:
self.add(p * 2 + 1, mid + 1, right, x)
self.lmx[p] = self.lmx[p * 2]
if self.lmx[p] == mid - left + 1:
self.lmx[p] += self.lmx[p * 2 + 1]
self.rmx[p] = self.rmx[p * 2 + 1]
if self.rmx[p] == right - mid:
self.rmx[p] += self.rmx[p * 2]
self.mx[p] = max(self.mx[p * 2], self.mx[p * 2 + 1])
self.mx[p] = max(self.mx[p], self.rmx[p * 2] + self.lmx[p * 2 + 1])
def largestRectangleArea(self, heights):
for i in range(0, len(heights)):
self.h.append((i, heights[i]))
self.h = sorted(self.h, key=lambda x:x[1])
self.h.reverse()
for i in range(0, 4 * len(self.h)):
self.lmx.append(0)
self.rmx.append(0)
self.mx.append(0)
ans = 0
for i in range(0, len(self.h)):
self.add(1, 0, len(self.h) - 1, self.h[i][0])
if self.mx[1] * self.h[i][1] > ans:
ans = self.mx[1] * self.h[i][1]
return ans
码码码,然后交上去了……一开始mid = int((left + right) / 2)
我写成了mid = (left + right) / 2
,然后变成实数除法(手动再见)。
改了这个bug再交,AC啦。诶诶诶怎么我跑了1324ms啊,别人平均都是50ms……
原来还有
O(n)
O
(
n
)
的做法啊……用单调栈维护,只需扫一遍就能出答案……垃圾Leetcode不给数据范围
贴一份别人的 O(n) O ( n ) 的代码(Python 2.7):
def largestRectangleArea(self, height):
height.append(0)
stack = [-1]
ans = 0
for i in xrange(len(height)):
while height[i] < height[stack[-1]]:
h = height[stack.pop()]
w = i - stack[-1] - 1
ans = max(ans, h * w)
stack.append(i)
height.pop()
return ans