Leetcode 221. Maximal Square 單調佇列和dp兩種思路求解
阿新 • • 發佈:2018-11-11
題意
- 給定一個0,1矩陣,希望找到矩陣中的一個面積最大的聯通正方形區域,這個區域中全是1
思路
- 基本思路:找面積最大的,其實就是找最長的邊長,我們的思路都是以這個為出發點的
dp思路
- 整體來看,就是一個二維dp,是這類矩陣問題的一個常用狀態設定方法: 的含義是以 為右下角的最大正方形邊長
- 然後遞推方程,我們一定是看 、 以及 了
- 通過觀察矩陣形狀,我們不難發現當 時,小的那個正方形決定了 為右下角這個正方形的邊長,這時
- 而當
時,左上角的位置是否為0決定了當前正方形的邊長,這時可以用個小trick,不用真去看左上角為
還是
,可以通過
去判斷一下(這個小trick意義不大,就是遞推形式上更像dp,2333),即
單調佇列思路
- 這個問題我們可以把行列分開來看
- 我們先對每一行單獨來看,計算第 個元素前有多少個連續的 ,存下來
- 再對每一列單獨去看,我們的任務就變成在一個一維陣列中,找到最長連續子段,這個子段上元素的最小值要大於等於子段的長度
- 這個很類似於滑動視窗最大值之類的問題,比較容易想到用一個單調佇列就可以了,具體操作可以參考實現
實現
- 單調佇列實現
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.size() == 0)
return 0;
int n = matrix.size(), m = matrix[0].size();
vector<vector<int>> a(n, vector<int>(m, 0));
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
if (matrix[i][j] == '0'){
a[i][j] = 0;
}
else{
if (j == 0){
a[i][j] = 1;
}
else{
a[i][j] += a[i][j - 1] + 1;
}
}
}
}
int ans = 0;
for (int j = 0; j < m; j++){
deque<pair<int, int> > q;
int len = 1;
for (int i = 0; i < n; i++){
while (q.size() && q.back().first > a[i][j]){
q.pop_back();
}
q.push_back(make_pair(a[i][j], i));
if (q.front().first < len){
len = i - q.front().second + 1;
q.pop_front();
}
else {
ans = max(ans, len);
len++;
}
}
}
return ans * ans;
}
};
- dp實現
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.size() == 0)
return 0;
int n = matrix.size(), m = matrix[0].size();
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
int ans = 0;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (matrix[i-1][j-1] == '0'){
continue;
}
if (dp[i-1][j] == dp[i][j-1]){
dp[i][j] = dp[i-1][j];
if (dp[i-1][j-1] >= dp[i-1][j]){
dp[i][j]++;
}
}
else{
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1;
}
ans = max(ans, dp[i][j]);
}
}
return ans * ans;
}
};