在Go(Golang)中找到直方图中最大的矩形区域的程序

245 阅读2分钟

概述

有一组条形图,每个条形图的宽度为1个单位,但高度不同,放在旁边。条形的高度用一个数组来表示

[2, 0 , 2, 1, 3, 1]

该数组表示

  • 条形的总数是5

  • 第一根柱子的高度是2

  • 第二根柱子的高度是0

  • 第三条的高度是2

  • 第四根柱子的高度是1

  • 第五根柱子的高度是3

  • 第六根柱子的高度为1

我们的目标是找到直方图中最大的矩形区域。从图中可以看出,最大的矩形区域是4。

下面是我们可以采取的方法来解决这个问题。我们将使用堆栈,假设条形图完全包含在最大的矩形区域内,将找出条形图每个索引的面积。

  • 将给定数组的第一个元素推到堆栈中。遍历给定的数组。对于每个条形,我们需要找出左边最近的小条形和右边最近的小条形。

  • 对于当前元素,检查顶部元素的高度是否大于当前元素的高度

  • 如果是,那么当前元素就是右边最近的小条。而在堆栈中位于顶部元素之后的元素是左侧最近的小条。

  • 弹出这个元素并计算最大的矩形区域,假设条形图被完全包括在内。追踪最大的矩形区域

  • 重复以上两个步骤,直到堆栈为空或顶层元素的高度小于当前元素。

  • 将当前元素推到堆栈中

  • 最后返回最大的矩形区域。

程序

以下是相同的程序。

package main

import "fmt"

type customStack struct {
	stack []int
}

func (c *customStack) Push(num int) {
	c.stack = append(c.stack, num)
}

func (c *customStack) Pop() (int, error) {
	length := len(c.stack)
	poppedItem := 0
	if length > 0 {
		poppedItem = c.stack[length-1]
		c.stack = c.stack[:length-1]
		return poppedItem, nil
	}
	return 0, fmt.Errorf("stack is empty")
}

func (c *customStack) Front() (int, error) {
	length := len(c.stack)
	if length > 0 {
		return c.stack[length-1], nil
	}
	return 0, fmt.Errorf("stack is empty")
}

func (c *customStack) Size() int {
	return len(c.stack)
}

func largestRectangleArea(heights []int) int {
	customStack := &customStack{}

	lenHeights := len(heights)

	customStack.Push(0)

	maxRectangleSize := heights[0]

	for i := 1; i < lenHeights; i++ {

		for customStack.Size() != 0 {
			current, _ := customStack.Front()
			if heights[current] > heights[i] {
				var rectangleUsingCurrentBar int
				current, _ := customStack.Pop()
				//Calcualte max rectangle using the current front
				previous, err := customStack.Front()
				if err != nil {
					previous = -1
				}
				rectangleUsingCurrentBar = (i - previous - 1) * heights[current]
				if rectangleUsingCurrentBar > maxRectangleSize {
					maxRectangleSize = rectangleUsingCurrentBar
				}
			} else {
				break
			}
		}
		customStack.Push(i)
	}

	front, err := customStack.Front()
	if err != nil {
		return maxRectangleSize
	}
	var rectangleUsingCurrentBar int
	for customStack.Size() != 0 {
		current, _ := customStack.Pop()
		previous, err := customStack.Front()
		if err != nil {
			previous = -1
		}
		rectangleUsingCurrentBar = (front - previous) * heights[current]
		if rectangleUsingCurrentBar > maxRectangleSize {
			maxRectangleSize = rectangleUsingCurrentBar
		}
	}
	return maxRectangleSize
}

func main() {
	output := largestRectangleArea([]int{2, 0, 2, 1, 3, 1})
	fmt.Println(output)
}

输出

4