Leetcode 第 129 场双周赛题解

Leetcode 第 129 场双周赛题解

题目1:3127. 构造相同颜色的正方形

思路

枚举 + 计数。

枚举矩阵中的每个 2×2 子矩形。

对于每个子矩形,统计 B 和 W 的个数,如果其中一个字母的出现次数 ≥3,则返回 true。

如果 4 个子矩形都不满足要求,返回 false。

代码

/*
 * @lc app=leetcode.cn id=3127 lang=cpp
 *
 * [3127] 构造相同颜色的正方形
 */

// @lc code=start
class Solution
{
public:
    bool canMakeSquare(vector<vector<char>> &grid)
    {
        // 判断以 (row, col) 为左上角的 2*2 的正方形是否满足要求
        auto check = [&](int row, int col) -> bool
        {
            int cntB = 0, cntW = 0;
            for (int i = row; i <= row + 1; i++)
                for (int j = col; j <= col + 1; j++)
                {
                    if (grid[i][j] == 'B')
                        cntB++;
                    else
                        cntW++;
                }
            return cntB >= 3 || cntW >= 3;
        };
        // 对于 3*3 的矩阵,只需要考虑 4 种情况
        return check(0, 0) || check(0, 1) || check(1, 0) || check(1, 1);
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(1)。

空间复杂度:O(1)。

题目2:3128. 直角三角形

思路

套路:有三个顶点,枚举「中间」的直角顶点更容易计算。

设第 i 行有 rows[i] 个 1,第 j 列有 cols[j] 个 1。根据乘法原理,直角顶点为 (i,j) 的直角三角形有 (rows[i] - 1) * (cols[j] - 1) 个,加到答案中。

代码

/*
 * @lc app=leetcode.cn id=3128 lang=cpp
 *
 * [3128] 直角三角形
 */

// @lc code=start
class Solution
{
public:
    long long numberOfRightTriangles(vector<vector<int>> &grid)
    {
        int m = grid.size(), n = m ? grid[0].size() : 0;
        // 每行 1 的个数
        vector<int> rows(m, 0);
        for (int i = 0; i < m; i++)
        {
            int row = 0;
            for (int j = 0; j < n; j++)
                row += grid[i][j];
            rows[i] = row;
        }
        // 每列 1 的个数
        vector<int> cols(n, 0);
        for (int j = 0; j < n; j++)
        {
            int col = 0;
            for (int i = 0; i < m; i++)
                col += grid[i][j];
            cols[j] = col;
        }
        long long ans = 0LL;
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
                if (grid[i][j] == 1)
                {
                    // 直角顶点为 (i,j) 的直角三角形有 (rows[i] - 1) * (cols[j] - 1) 个
                    ans += (rows[i] - 1) * (cols[j] - 1);
                }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(m*n),其中 m 和 n 分别是矩阵 grid 的行数和列数。

空间复杂度:O(m+n),其中 m 和 n 分别是矩阵 grid 的行数和列数。

题目3:3129. 找出所有稳定的二进制数组 I

思路

记忆化搜索。

dfs(i, j, count) 表示还剩 i 个 0,j 个 1,已经连用 count 个 i 对应的数字的组合数。

边界:dfs(0, 0, count) = 1。

转移为:

  1. 当 count == limit 时,换另一个数字开始计数 dfs(j-1, i, 1)
  2. 当 count < limit 时,为 dfs(i-1, j, count+1) + dfs(j-1, i, 1)

入口:dfs(zero, one, 0)。

代码

/*
 * @lc app=leetcode.cn id=3129 lang=cpp
 *
 * [3129] 找出所有稳定的二进制数组 I
 */

// @lc code=start
class Solution
{
private:
    const int MOD = 1e9 + 7;

public:
    int numberOfStableArrays(int zero, int one, int limit)
    {
        int mx = max(zero, one);
        int memo[mx + 1][mx + 1][limit + 1];
        memset(memo, -1, sizeof(memo));
        // 还剩 i 个 0,j 个 1,已经连续使用了 count 个 i 对应的数字
        function<int(int, int, int)> dfs = [&](int i, int j, int count) -> int
        {
            if (i < 0 || j < 0)
                return 0;
            if (i == 0 && j == 0)
                return 1;
            int &res = memo[i][j][count];
            if (res != -1)
                return res;
            if (count == limit)
            {
                // 换另一个数字开始计数
                res = dfs(j - 1, i, 1) % MOD;
            }
            else
            {
                // 两种都可以
                res = (dfs(i - 1, j, count + 1) + dfs(j - 1, i, 1)) % MOD;
            }
            return res;
        };
        return dfs(zero, one, 0);
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(zero*one*limit)。

空间复杂度:O(mx2*limit),其中 mx = max(zero, one)。

题目4:3130. 找出所有稳定的二进制数组 II

思路

题解:两种方法:动态规划 / 组合数学(Python/Java/C++/Go)

定义 dfs(i, j, k, limit) 为用 i 个 0,j 个 1 构造稳定数组的方案数,其中第 i+j 个位置要填 k,其中 k 为 0 或 1。

在这里插入图片描述

边界:

在这里插入图片描述

入口:dfs(zero, one, 0, limit) + dfs(zero, one, 1, limit)。

代码

/*
 * @lc app=leetcode.cn id=3130 lang=cpp
 *
 * [3130] 找出所有稳定的二进制数组 II
 */

// @lc code=start
class Solution
{
private:
    const int MOD = 1e9 + 7;

public:
    int numberOfStableArrays(int zero, int one, int limit)
    {
        int memo[zero + 1][one + 1][2];
        memset(memo, -1, sizeof(memo));
        // 用 i 个 0,j 个 1 构造稳定数组的方案数,其中第 i+j 个位置要填 k
        function<int(int, int, int, int)> dfs = [&](int i, int j, int k, int limit) -> int
        {
            if (i == 0)
            { // 递归边界
                return k == 1 && j <= limit;
            }
            if (j == 0)
            { // 递归边界
                return k == 0 && i <= limit;
            }

            int &res = memo[i][j][k];
            if (res != -1)
                return res;
            if (k == 0)
            {
                res = ((long long)dfs(i - 1, j, 0, limit) + dfs(i - 1, j, 1, limit) +
                       (i > limit ? MOD - dfs(i - limit - 1, j, 1, limit) : 0)) %
                      MOD;
            }
            else
            {
                res = ((long long)dfs(i, j - 1, 0, limit) + dfs(i, j - 1, 1, limit) +
                       (j > limit ? MOD - dfs(i, j - limit - 1, 0, limit) : 0)) %
                      MOD;
            }
            return res;
        };
        return (dfs(zero, one, 0, limit) + dfs(zero, one, 1, limit)) % MOD;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(zero*one)。

空间复杂度:O(zero*one)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值