85. 最大矩形
这题用到了前面84的思路,我先计算了一个数组,记录每一行从当前元素起有几个连续的1。然后对于每一列(从右到左,不过其实想想从左到右也没区别,当时想多了)把行数0~n-1作为横坐标,每个元素对应的连续1的长度作为高度,整体逆时针旋转90度就变成了84题求柱状图最大矩形的问题。对于每一列用递增栈O(N),共n列,总体复杂度O(N^2)。
class Solution:
def maximalRectangle(self, matrix) -> int:
area=0
m=len(matrix)
if not m:
return 0
n=len(matrix[0])
#m行n列
#算一个数组d,d[i,j]记录第i行第j列开始往后有几个连续的1
d=[[0 for i in range(n)] for j in range(m)]
for i in range(m):
#每行最后一个元素单拎出来
if matrix[i][-1]=='1':
d[i][-1]=1
for j in range(n-2,-1,-1):
#每行倒序进行
if matrix[i][j]=='1':
d[i][j]=d[i][j+1]+1
else:
d[i][j]=0
for col in range(n):
stack=[]
row=0
while row<m:
if not stack or d[row][col]>=d[stack[-1]][col]:
#栈空或当前高度比栈顶大则入栈
stack.append(row)
row+=1
else:
k=stack.pop()
area=max(area,((row-stack[-1]-1)if stack else row)*d[k][col])
while stack:
k=stack.pop()
area=max(area,((row-stack[-1]-1)if stack else row)*d[k][col])
return area
翻用时翻到大佬的,用二进制移位做,看都看了半天。。
给的数组只有1和0,先把每一行用join函数改为字符串再转为十进制数字,然后对于任意存在的矩形,设起始行为i,末尾行为j,必然应该满足i行与i+1到j的每一行的&(与)运算不为0,(两行与运算为0表示这两行不存在相同的位置都为1,则这两行显然构不成矩形),而j是从i+1开始往下遍历,若遇到某一行与i的与运算为0,则后面的就不用循环了,相当于有点DP的思想。然后
while tmp:
tmp &= (tmp << 1)
cnt += 1
这一句是计算tmp的二进制串中有几位连续的1,考虑其中最长连续的1有4个,每次tmp左移一位,再与它原本的值进行与运算,那么这四位最左一位就移出去了,右边的三位进行与运算结果还是三个1,然后再循环一次,剩下两个1,以此类推。
class Solution:
def maximalRectangle(self, matrix) -> int:
if not matrix or not matrix[0]:
return 0
nums = [int(''.join(s), 2) for s in matrix]
print(nums)
n = len(nums)
area = 0
for i in range(n):
num = nums[i]
for j in range(i, n):
num &= nums[j]
if not num: #做与运算结果为0意味i行为0的j行必为1或为0
#剩下的内层for循环也没必要继续了
break
cnt, tmp = 0, num
#下面这个while是计算tmp中有几个连续的1,真牛逼
while tmp:
tmp &= (tmp << 1)
cnt += 1
#cnt是当前矩形的横向的最大长度
#(j-i+1)为当前矩形的高
area = max(area, cnt * (j - i + 1))
return area
大佬??
进击的小🐴农