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

大佬??

posted @ 2019-08-06 01:59  NeoZy  阅读(86)  评论(0编辑  收藏  举报