20230703-CodeTop

100 阅读1分钟

今天做的都是动态规划,想恢复一下手感。前面做的打家劫舍、买卖股票的最佳时机2、3啥的没啥好记的。就最后这道题感觉有记的必要。

leetcode-221 最大正方形

这题说实话状态转移我想了半天都没想出来,一开始感觉有点像二维版的最长回文子串,就是里面是全1的正方形,那加上一圈'1'得到的也是全1正方形。但是这个思路没法写状态转移,而且加的也不一定是一整圈,可以只加两条相邻边。

最后看了题解才明白,思路应该是设dp[i][j]为以(i, j)位置为右下角的正方形的最大边长。这样一来状态就可以从左上角往右下角转移,状态转移的逻辑是取左侧、上侧、左上侧三个dp值的最小值+1。因为dp[i][j]需要同时满足3个正方形都能包含进去,只能取最小值其实也就是公共部分。base case考虑第一行第一列即可。

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