拿到这个问题很容易想到,对于每一个柱形图,只要向左向右去遍历,然后找到左边第一个小于他的点和右边第一个小于他的点,就可以得到宽度,然后再乘上它的高,就可以得到当前的矩形面积。从左到右依次遍历并且更新结果,最后就可以求得最大的矩形面积。
容易得到,这个解法的时间复杂度为O(n^2),那么怎么优化呢,首先要考虑,从左到右的遍历是免不了的,那么对于每一个点,求解它左右的第一个小于它的元素,这个点是不是可以优化呢。所以这里就用到了单调栈,我们可以花费一点空间,用一个栈来维护一组下标,对于栈中的每一个下标所对应的元素,它的左边第一个比他小的元素的下标就是栈中的前一个下标,有了这样的思路,就容易解决问题了。
class Solution(object):
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
stack = []
maxarea = 0
for i in range(len(heights)):
while stack and heights[i] <= heights[stack[-1]]:
peek = stack.pop()
maxleft = stack[-1] if stack else -1
curArea = (i - maxleft -1)*heights[peek]
maxarea = max(curArea,maxarea)
stack.append(i)
while stack:
peek = stack.pop()
maxleft = stack[-1] if stack else -1
curArea = (len(heights) - maxleft -1)*heights[peek]
maxarea = max(curArea,maxarea)
return maxarea
此题和84题一样的解法,同样是用单调栈,先给出一个辅助数组,记录是否遇到0,不是就加一,是就变0.
class Solution(object):
def maximalRectangle(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
if not matrix: return 0
maxarea = 0
dp = [0] * len(matrix[0])
for i in range(len(matrix)):
for j in range(len(matrix[0])):
# update the state of this row's histogram using the last row's histogram
# by keeping track of the number of consecutive ones
dp[j] = dp[j] + 1 if matrix[i][j] == '1' else 0
# update maxarea with the maximum area from this row's histogram
maxarea = max(maxarea, self.maxRect(dp))
return maxarea
def maxRect(self, heights):
stack = []
maxarea = 0
for i in range(len(heights)):
while stack and heights[i] <= heights[stack[-1]]:
peek = stack.pop()
maxleft = stack[-1] if stack else -1
curArea = (i - maxleft -1)*heights[peek]
maxarea = max(curArea,maxarea)
stack.append(i)
while stack:
peek = stack.pop()
maxleft = stack[-1] if stack else -1
curArea = (len(heights) - maxleft -1)*heights[peek]
maxarea = max(curArea,maxarea)
return maxarea
这题是153的延伸,区别就是允许重复数字的出现。因此增加了一个当first = mid = last时,按顺序查找最小值。(此题特别注意是各种等号要加进去,不然就会判断错误)
class Solution(object):
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
first = 0
last = len(nums) - 1
flag = 0
while nums[first] >= nums[last]:
flag = 1
if last - first == 1:
mid = last
break
mid = (first + last)//2
if nums[first] == nums[mid] and nums[mid] == nums[last]:
return self.inorderNum(nums,first,last)
if nums[mid] >= nums[first]:
first = mid
elif nums[mid] <= nums[first]:
last = mid
print(flag)
if flag == 0:
return nums[0]
else:
return nums[mid]
def inorderNum(self,nums,first,last):
result = nums[first]
for i in range(first+1,last+1):
if result > nums[i]:
result = nums[i]
return result