单调栈法

解题思路

本题可以转化为84题,只不过对每一行分别算一次柱形高度,然后带入84题的解法

84题解法

  • 1、用单调栈,如果碰到高度一直增高,很好,暂时不用求最大矩形面积,将当前的柱形索引依次入栈就好。

因为宽度在增大,高度还递增,最大矩形面积肯定一直增大的

  • 2、一旦碰到了一根较矮的柱形,设其索引为k,那么就要开始结算了。

结算方法为
1)只要栈不为空,栈顶高度比k高,就依次从栈顶出栈
2)设栈顶索引为topIndex,那么,以topIndex高度为height,以当前栈顶索引左边较矮的柱形和k夹板,求一次矩形的面积。
* 3)如果面积大于最大面积,更新最大面积

  • 3、为了方便处理第一个和最后一个柱形图,可以在两边加入两个哨兵,作为高度为0的夹板

时间复杂度:O(mn)。
空间复杂度:O(n)

  1. //单调栈实现,通法
  2. func maximalRectangle(matrix [][]byte) int {
  3. if matrix==nil || len(matrix)==0{
  4. return 0
  5. }
  6. //保存最终结果
  7. max:=0
  8. //行数,列数
  9. m,n:=len(matrix),len(matrix[0])
  10. //高度数组(统计每一行中1的高度)
  11. height:=make([]int,n)
  12. for i:=0;i<m;i++{
  13. for j:=0;j<n;j++{
  14. //每一行去找1的高度
  15. //如果不是‘1’,则将当前高度置为0
  16. if matrix[i][j]=='0'{
  17. height[j]=0
  18. }else{
  19. //是‘1’,则将高度加1
  20. height[j]=height[j]+1
  21. }
  22. }
  23. //更新最大矩形的面积
  24. max=int(math.Max(float64(max),float64(maxRectangle(height))))
  25. }
  26. return max
  27. }
  28. //使用84题的结果
  29. func maxRectangle(heights []int)int{
  30. //最大矩形面积
  31. maxarea:=0
  32. //定义栈
  33. stack:=make([]int,0)
  34. //放入-1在栈底是为了:如果矩形包括索引为0处的柱子,则左边界为0的左边,方便计算左边界的索引
  35. stack=append(stack,-1)
  36. for i:=0;i<len(heights);i++{
  37. //当下一个柱子的高度小于当前栈顶柱子的高度
  38. for stack[len(stack)-1]!=-1 && heights[stack[len(stack)-1]]>=heights[i]{
  39. //得到当前栈顶元素的索引
  40. tmp:=stack[len(stack)-1]
  41. //出栈
  42. stack=stack[:len(stack)-1]
  43. //更新面积
  44. maxarea=int(math.Max(float64(maxarea),float64(heights[tmp]*(i-stack[len(stack)-1]-1))))
  45. }
  46. //当新加入柱子的高度大于栈顶柱子的高度(满足升序)
  47. stack=append(stack,i)
  48. }
  49. //当遍历完数组时,判断栈是否为空
  50. for stack[len(stack)-1]!=-1{
  51. //得到当前栈顶元素索引
  52. tmp:=stack[len(stack)-1]
  53. //出栈
  54. stack=stack[:len(stack)-1]
  55. //更新面积
  56. maxarea=int(math.Max(float64(maxarea),float64(heights[tmp]*(len(heights)-1-stack[len(stack)-1]))))
  57. }
  58. return maxarea
  59. }
//动态规划(太菜了,照着官方解释看懂的,估计过几天又忘了)
func maximalRectangle(matrix [][]byte) int {
    if matrix==nil || len(matrix)==0{
        return 0
    }
    //保存结果
    maxarea:=0
    m,n:=len(matrix),len(matrix[0])
    height:=make([]int,n)
    left:=make([]int,n)
    right:=make([]int,n)
    //初始化
    for i:=0;i<n;i++{
        right[i]=n
    }
    for i:=0;i<m;i++{
        cur_left,cur_right:=0,n
        //更新height
        for j:=0;j<n;j++{
            if matrix[i][j]=='1'{
                height[j]++
            }else{
                height[j]=0
            }
        }
        //更新left
        for j:=0;j<n;j++{
            if matrix[i][j]=='1'{
                left[j]=int(math.Max(float64(left[j]),float64(cur_left)))
            }else{
                left[j]=0
                cur_left=j+1
            }
        }
        //更新right
        for j:=n-1;j>=0;j--{
            if matrix[i][j]=='1'{
                right[j]=int(math.Min(float64(right[j]),float64(cur_right)))
            }else{
                right[j]=n
                cur_right=j
            }
        }
        //更新最大面积
        for j:=0;j<n;j++{
            maxarea=int(math.Max(float64(maxarea),float64(height[j]*(right[j]-left[j]))))
        }
    }
    return maxarea
}