(LeetCode 221)最大正方形 [dp & 滾動數組]

題目:
在一個由 0 和 1 組成的二維矩陣內,找到只包含 1 的最大正方形,並返回其面積。
示例:

輸入: 
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

輸出: 4

分析:
方法一:

找出最大正方形的面積,換句話說就是找出最大正方形的邊長,面積爲邊長的平方。
使用 dp[i][j] = k 表示在矩陣位置(i,j)處,以(i,j)爲正方形的右下角的正方形的最大邊長爲 k
而一個以(i,j)爲正方形的右下角的正方形,可以分爲4部分:
1:以(i-1,j-1)爲右下角的邊長爲 k-1 的正方形
2:以(i-1,j)爲右下角的邊長爲 k-1 的正方形
3:以(i,j-1)爲右下角的邊長爲 k-1 的正方形
4:(i,j)處爲1
如下圖所示:
在這裏插入圖片描述
所以遞推公式爲:對於位子上爲‘1’的位置(i,j)
dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1

注意: 因爲我們是按照從左到右,從上到下的順序掃描的,所以當訪問某個新位置時,它的左上方是已知的,因此dp[i][j]是向左上角方向畫正方形。確保畫的方向的其他位置的結果值是已知的。

代碼:

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int maxlen = 0;
        int n = 0, m = 0;
        n = matrix.size();
        if(n == 0) return 0;
        m = matrix[0].size();
        int dp[n][m];
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(matrix[i][j] == '1')
                {
                    if(i>0 && j>0)
                    {
                        dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j],dp[i][j-1])) + 1;
                    }
                    else dp[i][j] = 1;
                }
                maxlen = max(maxlen, dp[i][j]);
            }
        }
        return maxlen * maxlen;
    }
};

方法二:
由方法一中的更新公式可知:dp[i][j] 的值只與它本行前一個值dp[i][j-1],和上一行dp[i-1][j],dp[i-1][j-1]有關。
即只與它相鄰的上一行和本行有關。
在這裏插入圖片描述
我們可以使用以爲數組解決問題,只需維護好上述所需的三個值即可。
當我們未更新dp[i]的值時,那麼dp[i]代表的就是它上一行的值,即dp[i-1][j]
當我們已經更新dp[i]的值時,那麼dp[i]代表的就是它本行的值,即dp[i][j]

如下圖所示:
在這裏插入圖片描述
當我們更新紅色塊dp[i]時,那麼在更新前dp[i]的值表示上一行dp[i-1][j]的值,
而我們是從左到右更新的,所以此時dp[i-1]必然已經更新了,表示的值爲dp[i][j-1]
爲了維護dp[i-1][j-1]的值,我們需要在更新dp[i-1]時將其值保存在 pre 變量中。

所以更新爲:dp[i] = min(pre, dp[i], dp[i-1])

代碼:

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int maxlen = 0;
        int n = 0, m = 0;
        n = matrix.size();
        if(n == 0) return 0;
        m = matrix[0].size();
        int dp[m], pre = 0;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                int tmp = dp[j];
                if(matrix[i][j] == '1')
                {
                    if(j>0)
                    {
                        dp[j] = min(pre, min(dp[j-1],dp[j])) + 1;
                    }
                    else dp[j] = 1;
                }
                else dp[j] = 0;
                maxlen = max(maxlen, dp[j]);
                pre = tmp;
            }
        }
        return maxlen * maxlen;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章