美团笔试最大矩形面积

给定一组非负整数组成的数组h,代表一组柱状图的高度,其中每个柱子的宽度都为1。 在这组柱状图中找到能组成的最大矩形的面积(如图所示)。 入参h为一个整型数组,代表每个柱子的高度,返回面积的值。
这个问题和前面我们讲过的一个盛最多水的容器很相似,不同的地方是这个边界可以不为首尾,因为内部也可能存在更大面积的矩形,而那个题目要求以两个边界为前提,组成的容器。上次我准备用dp来解决,没有成功,那是因为原理不符,没有最优子结构。这个问题就可以用dp来解决了。
首先我们来看,存在最优子结构,如果目前存在最大的矩形的面积,再加一个柱子,我们可以判断出加上它,最大的矩形面积。然后这个子问题也是重叠的,在加不加新柱子的问题上,我们判断最大矩形面积的方法是一样的,唯一不同的是边界不同,也就对应的参数不同。另外问题的边界也存在,就是我们输入的这几个高度。子问题的求解也是独立的。
int main()
{
    int n;
    cin >> n;
    vector<long> h(n+1);
    for (int i = 1; i <= n; i++)
        cin >> h[i];
    vector<vector<long>> dp(n+1, vector<long>(n+1));
    for (int i = 1; i <= n; i++)
        dp[i][i] = h[i];
    int min_h;
  //  for (int i = n-1; i >= 1; i--)
  //  {
        //for (int j = i; j <= n; j++)
  //      {
  //          min_h = h[i];
  //          for (int k = i; k <= j; k++)
  //              min_h = min_h < h[k] ? min_h : h[k];
  //          dp[i][j] = (min_h *(j - i + 1)) > dp[i][j - 1] ? (min_h *(j - i + 1)) : dp[i][j - 1];
  //          dp[j][i] = dp[i][j] = dp[i][j] > dp[i + 1][j] ? dp[i][j] : dp[i + 1][j];
  //      }
  //  }
    for (int j = 1; j<=n; j++)
    {
        for (int i = j-1; i >= 1; i--)
        {
            min_h = h[i];
            for (int k = i; k <= j; k++)
                min_h = min_h < h[k] ? min_h : h[k];
            dp[i][j] = (min_h *(j - i + 1)) > dp[i][j - 1] ? (min_h *(j - i + 1)) : dp[i][j - 1];
            dp[j][i] = dp[i][j] = dp[i][j] > dp[i + 1][j] ? dp[i][j] : dp[i + 1][j];
        }
    }
    for(int i=0;i<=n;i++)
    {
    cout << dp[1][i] << '\0';
    }
    return 0;
}

这里面,dp[i][j]代表从i到j的最大矩形面积。首先dp[i][i]就是该高度下的单个矩形面积。我们需要存储从i到j的最小高度,因为多加一个柱状图,我们需要判断以最小高度为高的矩形面积,比原来的最大矩形面积相比的结果。我们需要通过比较dp[i][j-1]和dp[i+1][j]以及新计算的面积三个来得到dp[i][j]。程序中加黑字体中,第一行将dp[i][j-1]和新面积相比,将最大值赋给了dp[i][j],但是这并不是最终的结果,因为如果dp[i+1][j]中的面积要大于这两个,我们就会漏掉。所以第二行也很必要。一定不能丢。

上述的过程不好理解的话,就理解下边界情况,如果就两个直方图,我们需要比较这两个单独的面积以及两个并在一起的面积,必须比较完这三个才能得到最大的面积。

(2)其实这道题还可以用单调栈来做,具体做法见上一篇《单调栈以及应用》,这里不再赘述。

猜你喜欢

转载自www.cnblogs.com/mini-coconut/p/9108434.html
今日推荐