[程式設計師程式碼面試指南] 求最大子矩陣的大小
阿新 • • 發佈:2019-01-02
[程式設計師程式碼面試指南] 求最大子矩陣的大小
題目描述:
給定一個整型的矩陣,其中只有0和1兩種值.
求其中 最大的全是1 的 矩形
區域的大小
如:
1 1 1 0
最大區域為 3
再如:
1 0 1 1
1 1 1 1
1 1 1 0
最大矩陣區域為 6
分析:
-
將矩陣看做一行一行的.求每一行為底的,每個位置往上
1
的個數.用高度陣列height
表示. -
對於每一次切割獲得的
height
陣列,求其中每一個柱子,求能向左以及向右擴充套件到第一個比它小的地方.
使用棧來實現第二點:
從左到右遍歷陣列height,遍歷到i元素:
-
若
i
位置的值大於棧頂位置所代表的值,直接將i
入棧那麼,這個棧保持的就是
遞增
的. -
若當前元素
小於或者等於
當前元素棧頂
位置所代表的值,那麼就是要不斷地出棧,直至棧頂元素所代表的值小於
i
表示的值.再把i
入棧.在彈出的過程中,
假設當前彈出的棧頂位置為
j
. 彈出之後,棧頂為k
-
對於柱子
j
向右最遠能擴到i-1
.若所有元素入棧之後,那麼棧不為空,則向右最遠可以到
height.size
; -
對於柱子
j
,向左最遠可以擴充套件到k+1
. (為什麼是k+1
呢,因為k
位置肯定比j
位置的小,入棧時候的規則,保證了這個棧是遞增的)若棧此時為空,那麼它可以最遠擴充套件到0.
-
實現:
int maxRecSize(vector<vector<int>> map) { // 異常處理 if (map.size() == 0) { return 0; } if (map[0].size() == 0) { return 0; } int rows = map.size(); int cols = map[0].size(); vector<int> height(cols, 0); int res = 0; // 更新每一層為底的最大矩陣大小 for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { // 更新height陣列 height[j] = map[i][j] == 0 ? 0 : height[j] + 1; } res = max(res, maxRecFromBottom(height)); } return res; } // 考察每一根柱子最大能擴散到哪裡,找到柱子左邊比它小的位置,以及找到右邊比他小的位置. int maxRecFromBottom(vector<int> height) { int res = 0; stack<int> m_stack; // 存放的是索引 for (int i = 0; i < height.size(); i++) { while (!m_stack.empty() && height[i] <= height[m_stack.top]) { int j = m_stack.top(); m_stack.pop(); int k = m_stack.empty() ? -1 : m_stack.top(); // 若為空,表示向左最遠可以到0位置 int curArea = height[j] * ((i - 1) - (k + 1) + 1); // 其是 height[j] * (i-k-1); res = max(res, curArea); } m_stack.push(i); } while (!m_stack.empty()) { // 若棧不為空,表示向右最遠可以到height.size()的位置 int j = m_stack.top(); m_stack.pop(); int k = m_stack.empty() ? -1 : m_stack.top(); int curArea = height[j] * ((height.size() - 1) - (k + 1) + 1); // 其是 height[j] * (i-k-1); res = max(res, curArea); } return res; }
體會:
棧
經常用來儲存保證一個遞增或者遞減的性質,然後不滿足性質,就通過出棧來更新要輸出的資訊.- 切割陣列的方法,將二維矩陣看做一層層的.