Leetcode 第 405 场周赛题解

Leetcode 第 405 场周赛题解

题目1:3210. 找出加密后的字符串

思路

字符串截取。

注意 k 要对 s.size() 取余。

代码

/*
 * @lc app=leetcode.cn id=3210 lang=cpp
 *
 * [3210] 找出加密后的字符串
 */

// @lc code=start
class Solution
{
public:
    string getEncryptedString(string s, int k)
    {
        k %= s.size();
        string tmp1 = s.substr(0, k);
        string tmp2 = s.substr(k);
        return tmp2 + tmp1;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n),其中 n 是字符串 s 的长度。

空间复杂度:O(n),其中 n 是字符串 s 的长度。

题目2:3211. 生成不含相邻零的二进制字符串

思路

回溯。

可以使用回溯得到所有长度为 n 的有效字符串。

字符串的每个位置都需要填入 0 或 1。对于 0≤i<n,如果 i=0 或字符串的下标 i−1 处填入 1,则字符串的下标 i 处可以填入 0 或 1,否则字符串的下标 i 处只能填入 1。

上述操作可以确保得到有效字符串,当得到一个长度为 n 的有效字符串时,将该字符串添加到结果列表中。回溯结束之后即可得到所有长度为 n 的有效字符串。

代码

/*
 * @lc app=leetcode.cn id=3211 lang=cpp
 *
 * [3211] 生成不含相邻零的二进制字符串
 */

// @lc code=start
class Solution
{
private:
    bool check(string &s)
    {
        int n = s.size();
        for (int i = 0; i < n - 1; i++)
            if (s[i] == '0' && s[i + 1] == '0')
                return false;
        return true;
    }

public:
    vector<string> validStrings(int n)
    {
        vector<string> ans;
        string cur = "";
        backtrack(cur, 0, n, ans);
        return ans;
    }
    // 辅函数- 回溯
    void backtrack(string &cur, int level, int n, vector<string> &ans)
    {
        if (level > n)
            return;
        if (level == n && check(cur))
        {
            ans.push_back(cur);
            return;
        }
        
        cur.push_back('0');
        level++;
        backtrack(cur, level, n, ans);
        level--;
        cur.pop_back();

        cur.push_back('1');
        level++;
        backtrack(cur, level, n, ans);
        level--;
        cur.pop_back();
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n*2n),其中 n 是给定的有效字符串长度。有效字符串个数不超过 2n,每个有效字符串添加到答案中的时间是 O(n),因此时间复杂度是 O(n*2n)。

空间复杂度:O(n),其中 n 是给定的有效字符串长度。存储当前有效字符串的临时空间和递归调用栈空间是 O(n)。注意返回值不计入空间复杂度。

题目3:3212. 统计 X 和 Y 频数相等的子矩阵数量

思路

维护二维前缀和,分别统计 ‘X’ 和 ‘Y’ 的个数。

统计足以下条件的子矩阵数量:

  • 包含 grid[0][0]
  • ‘X’ 和 ‘Y’ 的频数相等。
  • 至少包含一个 ‘X’。

代码

/*
 * @lc app=leetcode.cn id=3212 lang=cpp
 *
 * [3212] 统计 X 和 Y 频数相等的子矩阵数量
 */

// @lc code=start
class Solution
{
public:
    int numberOfSubmatrices(vector<vector<char>> &grid)
    {
        int m = grid.size(), n = m ? grid[0].size() : 0;
        vector<vector<pair<int, int>>> sum(m + 1, vector(n + 1, pair<int, int>()));

        int ans = 0;
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
            {
                sum[i + 1][j + 1].first = sum[i + 1][j].first + sum[i][j + 1].first - sum[i][j].first;
                sum[i + 1][j + 1].second = sum[i + 1][j].second + sum[i][j + 1].second - sum[i][j].second;
                if (grid[i][j] == 'X')
                    sum[i + 1][j + 1].first++;
                else if (grid[i][j] == 'Y')
                    sum[i + 1][j + 1].second++;
                if (sum[i + 1][j + 1].first && sum[i + 1][j + 1].first == sum[i + 1][j + 1].second)
                    ans++;
            }
        return ans;
    }
};
// @lc code=end

复杂度分析

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

空间复杂度:O(m*n),其中 m 和 n 分别为 grid 的行数和列数。

题目4:3213. 最小代价构造字符串

思路

题解:三种方法:字符串哈希 / 后缀数组 / AC 自动机(Python/Java/C++/Go)

代码

/*
 * @lc app=leetcode.cn id=3213 lang=cpp
 *
 * [3213] 最小代价构造字符串
 */

// @lc code=start
class Solution
{
public:
    int minimumCost(string target, vector<string> &words, vector<int> &costs)
    {
        int n = target.length();

        // 多项式字符串哈希(方便计算子串哈希值)
        // 哈希函数 hash(s) = s[0] * base^(n-1) + s[1] * base^(n-2) + ... + s[n-2] * base + s[n-1]
        const int MOD = 1'070'777'777;
        mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
        const int BASE = uniform_int_distribution<>(8e8, 9e8)(rng); // 随机 base,防止 hack
        vector<int> pow_base(n + 1);                                // pow_base[i] = base^i
        vector<int> pre_hash(n + 1);                                // 前缀哈希值 pre_hash[i] = hash(s[:i])
        pow_base[0] = 1;
        for (int i = 0; i < n; i++)
        {
            pow_base[i + 1] = (long long)pow_base[i] * BASE % MOD;
            pre_hash[i + 1] = ((long long)pre_hash[i] * BASE + target[i]) % MOD; // 秦九韶算法计算多项式哈希
        }

        // 计算 target[l] 到 target[r-1] 的哈希值
        auto sub_hash = [&](int l, int r)
        {
            return ((pre_hash[r] - (long long)pre_hash[l] * pow_base[r - l]) % MOD + MOD) % MOD;
        };

        map<int, unordered_map<int, int>> min_cost; // 长度 -> 哈希值 -> 最小成本
        for (int i = 0; i < words.size(); i++)
        {
            long long h = 0;
            for (char b : words[i])
            {
                h = (h * BASE + b) % MOD;
            }
            int m = words[i].length();
            if (min_cost[m].find(h) == min_cost[m].end())
            {
                min_cost[m][h] = costs[i];
            }
            else
            {
                min_cost[m][h] = min(min_cost[m][h], costs[i]);
            }
        }

        vector<int> f(n + 1, INT_MAX / 2);
        f[0] = 0;
        for (int i = 1; i <= n; i++)
        {
            for (auto &[len, mc] : min_cost)
            {
                if (len > i)
                {
                    break;
                }
                auto it = mc.find(sub_hash(i - len, i));
                if (it != mc.end())
                {
                    f[i] = min(f[i], f[i - len] + it->second);
                }
            }
        }
        return f[n] == INT_MAX / 2 ? -1 : f[n];
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(L+sqrt(L)),其中 n 是 target 的长度,L 是 words 中所有字符串的长度之和。

空间复杂度:O(n+m)。其中 m 是 words 的长度。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

UestcXiye

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

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

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

打赏作者

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

抵扣说明:

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

余额充值