題目描述
給定 n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度爲 1 。
求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。
以上是柱狀圖的示例,其中每個柱子的寬度爲 1,給定的高度爲 [2,1,5,6,2,3]。
圖中陰影部分爲所能勾勒出的最大矩形面積,其面積爲 10 個單位。
示例:
輸入: [2,1,5,6,2,3]
輸出: 10
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
白話題目:
算法:
詳細解釋關注 B站 【C語言全代碼】學渣帶你刷Leetcode 不走丟 https://www.bilibili.com/video/BV1C7411y7gB
C語言完全代碼
//方法二:單調棧(學習)
//1,使用數組 StackArray 模擬棧的使用
//2,如果 heights[i] > heights[i+1] 則將 棧中所有大於 heights[i+1]的 元素出棧,並計算最大面積
//3,如果 heights[i] <= heights[i+1] 則將 元素入棧
//4,最後將棧中所有元素出棧,並計算最大面積
#define MAX_II(a, b) ((a) > (b) ? (a) : (b))
int largestRectangleArea(int* heights, int heightsSize){
int i = 0;
int iTop = 0;
int iTmpMax = 0;
int iTmpCur = 0;
int* pHeight = NULL;
int StackArray[heightsSize + 2];
if((NULL == heights) || (0 == heightsSize)) return 0;
pHeight = (int*)malloc(sizeof(int) * (heightsSize + 2));
memset(pHeight, 0x00, sizeof(int) * (heightsSize + 2));
memcpy(&pHeight[1], &heights[0], sizeof(int) * heightsSize);
memset(StackArray, 0x00, sizeof(int) * (heightsSize + 2));
//1, 默認棧底 StackArray[0]=0
iTop = 1;
//調換2,3的順序,簡化操作,先判斷元素是否可以直接出棧計算面積,並且將棧能出棧的都出棧
for(i = 1; i <= heightsSize + 1; i++)
{
//3,出棧操作
while(pHeight[StackArray[iTop - 1]] > pHeight[i])
{
iTmpCur = (i - StackArray[iTop - 2] - 1) * pHeight[StackArray[iTop - 1]];
iTmpMax = MAX_II(iTmpCur, iTmpMax);
iTop -= 1;
}
//2,入棧操作
StackArray[iTop] = i;
iTop += 1;
}
return iTmpMax;
}
/*
//方法一:暴力法
//1,循環遍歷數組
//2,求每一個 i 對應的左邊 iLeft 和右邊 iRight
//3,計算每一個i對應的矩形面積,求出其中最大值
#define MAX_III(a, b, c) ((a) > ((b) > (c) ? (b) : (c)) ? (a) : ((b) > (c) ? (b) : (c)))
#define MAX_II(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int largestRectangleArea(int* heights, int heightsSize){
int i = 0;
int j = 0;
int iLeft = 0;
int iRight = 0;
int iTmpMax = 0;
int iTmpCur = 0;
int* pHeight = NULL;
if((NULL == heights) || (0 == heightsSize)) return 0;
pHeight = (int*)malloc(sizeof(int) * (heightsSize + 2));
memset(pHeight, 0x00, sizeof(int) * (heightsSize + 2));
memcpy(&pHeight[1], &heights[0], sizeof(int) * heightsSize);
for(i = 1; i <= heightsSize; i++)
{
//1,求左邊
for(j = i - 1; j >= 0; j--)
if(pHeight[j] < pHeight[i])
{
iLeft = j;
break;
}
}
//2,求右邊
for(j = i + 1; j <= heightsSize + 1; j++)
{
if(pHeight[j] < pHeight[i])
{
iRight = j;
break;
}
}
//3,求面積
iTmpCur = (iRight - iLeft - 1) * pHeight[i];
iTmpMax = MAX_II(iTmpCur, iTmpMax);
}
return iTmpMax;
}
*/
/*
//方法三:動態規劃算法優化
//1,如何求dp[i][j],
//2, if(i<heights[i-1]) dp[i][j]=max(dp[i][j-1],dp[i-1][heights[i-1]], S[i][j])
//3, S[i][j]爲以i,j爲座標往前找能畫出的最大面積
//優化 dp[][], dp[i][j-1],dp[i-1][heights[i-1]] 兩個值都可以用臨時變量代替
//解決 dp 空間問題
//優化循環處理,解決時間超時問題,j沒有必要從1開始執行
//設置兩個錨點,
//1,一個就是整個數組中最小值,每個 i 都需要計算一次最小j 時的面積
//2,一個就是當前j前面一個拐點,就是前面柱狀圖由低變高的拐點
//計算步驟:
//1,每個 i 的值都計算用 pHeight[1] 到 pHeight[i] 計算矩形面積
//問題,隨着I的增加,循環次數增加,每次找左邊的時間增加,導致超時
//優化,能不能把左邊 k 通過每次本身的循環就固定下來
#define MAX_III(a, b, c) ((a) > ((b) > (c) ? (b) : (c)) ? (a) : ((b) > (c) ? (b) : (c)))
#define MAX_II(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAXNUM 20000
int largestRectangleArea(int* heights, int heightsSize){
int i = 0;
int j = 0;
int k = 0;
int iTmpS = 0;
int iTmpMax = 0;
int iTmpCur = 0;
int* pHeight = NULL;
int* pTmpK = NULL;
bool bFlag = true;
if((NULL == heights) || (0 == heightsSize)) return 0;
pHeight = (int*)malloc(sizeof(int) * (heightsSize + 2));
memset(pHeight, 0x00, sizeof(int) * (heightsSize + 2));
memcpy(&pHeight[1], &heights[0], sizeof(int) * heightsSize);
pTmpK = (int*)malloc(sizeof(int) * (heightsSize + 1));
memset(pTmpK, 0x00, sizeof(int) * (heightsSize + 1));
for(i = 1; i <= heightsSize; i++)
{
if((bFlag) && (pHeight[i] == 1))
{
iTmpCur += pHeight[i];
iTmpMax = MAX_II(iTmpCur, iTmpMax);
continue;
}
bFlag = false;
//計算 pHeight[1] 到 pHeight[i] 的矩形面積
for(j = 1; j <= i; j++)
{
if(pHeight[i] < pHeight[i - 1])
{
if(pHeight[j] > pHeight[i])
{
pTmpK[j] = i;
}
else
{
for(k = i - 1; k > 0; k--)
{
if(pHeight[k] < pHeight[j])
{
break;
}
else
{
pTmpK[k] = i;
}
}
pTmpK[j] = k;
}
}
else
{
if(pHeight[j] > pHeight[i])
{
pTmpK[j] = i;
}
pTmpK[i] = i - 1;
}
iTmpS = (i - pTmpK[j]) * MIN(pHeight[i], pHeight[j]);
iTmpCur = MAX_III(iTmpCur, iTmpMax, iTmpS);
}
iTmpMax = MAX_II(iTmpCur, iTmpMax);
}
return iTmpMax;
}
*/
/*
#define MAX_III(a, b, c) ((a) > ((b) > (c) ? (b) : (c)) ? (a) : ((b) > (c) ? (b) : (c)))
#define MAX_II(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int largestRectangleArea(int* heights, int heightsSize){
int i = 0;
int j = 0;
int k = 0;
int iTmpS = 0;
int iTmpMax = 0;
int iTmpCur = 0;
int* pHeight = NULL;
if((NULL == heights) || (0 == heightsSize)) return 0;
pHeight = (int*)malloc(sizeof(int) * (heightsSize + 2));
memset(pHeight, 0x00, sizeof(int) * (heightsSize + 2));
memcpy(&pHeight[1], &heights[0], sizeof(int) * heightsSize);
for(i = 1; i <= heightsSize; i++)
{
//計算 pHeight[1] 到 pHeight[i] 的矩形面積
for(j = 1; j <= i; j++)
{
for(k = i - 1; k > 0; k--)
{
if(pHeight[k] < pHeight[j])
{
break;
}
}
iTmpS = (i - k) * MIN(pHeight[i], pHeight[j]);
iTmpCur = MAX_III(iTmpCur, iTmpMax, iTmpS);
// printf("[2][i=%d][j=%d][k=%d][iTmpS=%d][iTmpCur=%d][iTmpMax=%d]\n",
// i, j, k, iTmpS, iTmpCur, iTmpMax);
}
iTmpMax = MAX_II(iTmpCur, iTmpMax);
}
return iTmpMax;
}
*/
/*
//計算步驟:
//1,計算最小高度是的面積
//2,計算拐點時的面積
//3,拐點後按照 pHeight[k] 的值進行跳躍式計算
//需要記錄圖形中每一個拐點,每一個i 時,需要計算每個拐點的面積,
//1,首先需要計算每一個拐點的面積
//2,然後再以最後一個拐點後,按照 pHeight[k] 的值進行跳躍式計算
#define MAX_III(a, b, c) ((a) > ((b) > (c) ? (b) : (c)) ? (a) : ((b) > (c) ? (b) : (c)))
#define MAX_II(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
struct TrunPoint {
int iTrunI;
int iTrunJ
};
int largestRectangleArea(int* heights, int heightsSize){
int i = 0;
int j = 0;
int k = 0;
int iTmpS = 0;
int iTmpMax = 0;
int iTmpCur = 0;
int* pHeight = NULL;
int iNum = 0;
int iPointNum = 0;
struct TrunPoint* pTrunPoint = NULL;
if((NULL == heights) || (0 == heightsSize)) return 0;
pHeight = (int*)malloc(sizeof(int) * (heightsSize + 2));
memset(pHeight, 0x00, sizeof(int) * (heightsSize + 2));
memcpy(&pHeight[1], &heights[0], sizeof(int) * heightsSize);
pTrunPoint = (struct TrunPoint*)malloc(sizeof(struct TrunPoint) * (heightsSize + 1));
memset(pTrunPoint, 0x00, sizeof(struct TrunPoint) * (heightsSize + 1));
pTrunPoint[0].iTrunI = 0;
pTrunPoint[0].iTrunI = 0;
iPointNum = 1;
for(i = 1; i <= heightsSize; i++)
{
if(0 == pHeight[i - 1])
{
iTmpCur = pHeight[i];
iTmpMax = MAX_II(iTmpCur, iTmpMax);
continue;
}
if((pHeight[i] <= pHeight[i - 1]) && (pHeight[i] < pHeight[i + 1]))
{
pTrunPoint[iPointNum].iTrunI = i;
pTrunPoint[iPointNum].iTrunJ = pHeight[i];
iPointNum += 1;
printf("[0][Num=%d][i=%d][j=%d]\n", iPointNum, i, pHeight[i]);
}
if(iPointNum > 1)
{
//計算所有拐點面積
for(iNum = 1; iNum < iPointNum; iNum++)
{
j = pTrunPoint[iNum].iTrunJ;
if (j <= pHeight[i])
{
for(k = i - 1; k > 0; k--)
{
if(pHeight[k] < j)
{
break;
}
}
iTmpS = (i - k) * j;
iTmpCur = MAX_III(iTmpCur, iTmpMax, iTmpS);
printf("[1][Num=%d][iTrunI=%d][iTrunJ=%d][i=%d][j=%d][k=%d][iTmpS=%d][iTmpCur=%d][iTmpMax=%d]\n",
iNum, pTrunPoint[iNum].iTrunI, pTrunPoint[iNum].iTrunJ, i, j, k, iTmpS, iTmpCur, iTmpMax);
}
}
}
//計算最後一個拐點之後的所有 i 的面積
for(j = pTrunPoint[iPointNum - 1].iTrunJ + 1; j <= pHeight[i]; j++)
{
for(k = i - 1; k > 0; k--)
{
if(pHeight[k] < j)
{
break;
}
}
j = MIN(pHeight[k + 1], pHeight[i]);
iTmpS = (i - k) * j;
iTmpCur = MAX_III(iTmpCur, iTmpMax, iTmpS);
printf("[2][i=%d][j=%d][k=%d][iTmpS=%d][iTmpCur=%d][iTmpMax=%d]\n",
i, j, k, iTmpS, iTmpCur, iTmpMax);
}
iTmpMax = MAX_II(iTmpCur, iTmpMax);
}
return iTmpMax;
}
*/
/*
//方法二:動態規劃算法優化
//1,如何求dp[i][j],
//2, if(i<heights[i-1]) dp[i][j]=max(dp[i][j-1],dp[i-1][heights[i-1]], S[i][j])
//3, S[i][j]爲以i,j爲座標往前找能畫出的最大面積
//優化 dp[][], dp[i][j-1],dp[i-1][heights[i-1]] 兩個值都可以用臨時變量代替
//解決 dp 空間問題
#define MAX_III(a, b, c) ((a) > ((b) > (c) ? (b) : (c)) ? (a) : ((b) > (c) ? (b) : (c)))
#define MAX_II(a, b) ((a) > (b) ? (a) : (b))
int largestRectangleArea(int* heights, int heightsSize){
int i = 0;
int j = 0;
int k = 0;
int iTmpS = 0;
int iTmpMax = 0;
int iTmpCur = 0;
int* pHeight = NULL;
if((NULL == heights) || (0 == heightsSize)) return 0;
pHeight = (int*)malloc(sizeof(int) * (heightsSize + 1));
memset(pHeight, 0x00, sizeof(int) * (heightsSize + 1));
memcpy(&pHeight[1], &heights[0], sizeof(int) * heightsSize);
for(i = 1; i <= heightsSize; i++)
{
if(0 == pHeight[i - 1])
{
iTmpCur = pHeight[i];
iTmpMax = MAX_II(iTmpCur, iTmpMax);
continue;
}
for(j = 1; (j > 0) && (j <= pHeight[i]); j++)
{
for(k = i - 1; k > 0; k--)
{
if(pHeight[k] < j)
{
break;
}
}
iTmpS = (i - k) * j;
iTmpCur = MAX_III(iTmpCur, iTmpMax, iTmpS);
}
iTmpMax = MAX_II(iTmpCur, iTmpMax);
}
return iTmpMax;
}
*/
/*
//方法一:動態規劃算法
//1,如何求dp[i][j],
//2, if(i<heights[i-1]) dp[i][j]=max(dp[i][j-1],dp[i-1][heights[i-1]], S[i][j])
//3, S[i][j]爲以i,j爲座標往前找能畫出的最大面積
#define MAX(a, b, c) ((a) > ((b) > (c) ? (b) : (c)) ? (a) : ((b) > (c) ? (b) : (c)))
int largestRectangleArea(int* heights, int heightsSize){
int i = 0;
int j = 0;
int k = 0;
int iHMax = 1000;
int iTmpS = 0;
int iHeight = 0;
int dp[heightsSize + 1][iHMax];
int* pHeight = NULL;
if((NULL == heights) || (0 == heightsSize)) return 0;
pHeight = (int*)malloc(sizeof(int) * (heightsSize + 1));
memset(pHeight, 0x00, sizeof(int) * (heightsSize + 1));
memcpy(&pHeight[1], &heights[0], sizeof(int) * heightsSize);
memset(dp, 0x00, sizeof(int) * (heightsSize + 1) * iHMax);
for(i = 1; i <= heightsSize; i++)
{
for(j = 0; j <= pHeight[i]; j++)
{
if(j == 0)
{
dp[i][j] = dp[i - 1][pHeight[i - 1]];
continue;
}
for(k = i - 1; k > 0; k--)
{
if(pHeight[k] < j)
{
break;
}
}
iTmpS = (i - k) * j;
printf("[1][i=%d][j=%d][k=%d][dp[%d][%d]=%d][dp[%d][%d]=%d][iTmpS=%d]\n",
i, j, k, i, j - 1, dp[i][j - 1], i - 1, pHeight[i - 1], dp[i - 1][pHeight[i - 1]], iTmpS);
dp[i][j] = MAX(dp[i][j - 1], dp[i - 1][pHeight[i - 1]], iTmpS);
}
}
return dp[heightsSize][pHeight[heightsSize]];
}
*/