Leetcode 第 374 场周赛题解

Leetcode 第 374 场周赛题解

题目1:2951. 找出峰值

思路

遍历。

代码

/*
 * @lc app=leetcode.cn id=2951 lang=cpp
 *
 * [2951] 找出峰值
 */

// @lc code=start
class Solution
{
   
public:
    vector<int> findPeaks(vector<int> &mountain)
    {
   
        vector<int> peaks;
        for (int i = 1; i < mountain.size() - 1; i++)
            if (mountain[i] > mountain[i - 1] && mountain[i] > mountain[i + 1])
                peaks.push_back(i);
        return peaks;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n),其中 n 是数组 mountain 的长度。

空间复杂度:O(1)。

题目2:2952. 需要添加的硬币的最小数量

思路

贪心。

为方便处理,首先将数组 coins 按升序排序,然后计算需要添加的硬币的最小数量。

关键结论:对于正整数 x,如果区间 [1,x−1] 内的所有金额都可取得,且 x 在数组中,则区间 [1,2x−1] 内的所有金额也都可取得。

假设金额 x 不可取得,则至少需要在数组中添加一个小于或等于 x 的数,才能取得 x,否则无法取得 x。

如果区间 [1,x−1] 内的所有金额都可取得,则从贪心的角度考虑,添加 x 之后即可取得 x,且满足添加的金额个数最少。在添加 x 之后,区间 [1,2x−1] 内的所有金额都可取得,下一个不可取得的金额一定不会小于 2x。

由此可以提出一个贪心的方案。每次找到不可取得的最小的金额 x,在数组中添加 x,然后寻找下一个不可取得的最小的整数,重复上述步骤直到区间 [1,target] 中的所有金额都可取得。

代码

/*
 * @lc app=leetcode.cn id=2952 lang=cpp
 *
 * [2952] 需要添加的硬币的最小数量
 */

// @lc code=start
class Solution
{
   
public:
    int minimumAddedCoins(vector<int> &coins, int target)
    {
   
        sort(coins.begin(), coins.end());
        int x = 1, index = 0;
        int ans = 0;
        while (x <= target)
        {
   
            if (index < coins.size() && coins[index] <= x)
            {
   
                // 可取得的区间从 [1, x−1] 扩展到 [1, x+coins[index]−1]
                x += coins[index];
                index++;
            }
            else
            {
   
                // 可取得的区间从 [1, x−1] 扩展到 [1, 2x-1]
                x = 2 * x;
                ans++;
            }
        }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(nlogn+log(target)),其中 n 是数组 coins 的长度,target 是给定的正整数。将数组 coins 排序需要 O(nlog⁡n) 的时间,排序后需要遍历数组中的 n 个元素,以及更新 x 的值,由于 x 的值上限为 target,因此对 x 的值乘以 2 的操作不会超过 log⁡(target) 次,故时间复杂度是 O(n+log(⁡target))。

空间复杂度:O(logn),其中 n 是数组 coins 的长度。主要为排序的递归调用栈空间。

题目3:2953. 统计完全子字符串

思路

分组循环 + 滑动窗口。

「相邻字母相差至多为 2」这个约束把 word 划分成了多个子串 s,每个子串分别处理。可以用分组循环找到每个子串 s。

对于每个子串,由于每个字符恰好出现 k 次,我们可以枚举有 m 种字符,这样问题就变成了:

长度固定为 m*k 的滑动窗口,判断每种字符是否都出现了恰好 k 次。

代码

/*
 * @lc app=leetcode.cn id=2953 lang=cpp
 *
 * [2953] 统计完全子字符串
 */

// @lc code=start
class Solution
{
   
public:
    int countCompleteSubstrings(string word, int k)
    {
   
        int n = word.size();
        int ans = 0;
        for (int i = 0; i < n;)
        {
   
            int start = i;
            i++;
            while (i < n && abs(int(word[i]) - int(word[i - 1])) <= 2)
                i++;
            ans += countCompleteStrings(word.substr(start, i - start), k);
        }
        return ans;
    }
    // 辅函数 - 计算字符串 s 中完全子字符串的个数
    int countCompleteStrings(string s, int k)
    {
   
        int count = 0;
        for (int m = 1; m <= 26 && m * k <= s.length(); m++)
        {
   
            vector<int> alphaCount(26, 0);
            // 判断每种字符是否都出现了恰好 k 次
            auto check = [&]() -> bool
            {
   
                for (int i = 0; i < 26; i++)
                {
   
                    if (alphaCount[i] && alphaCount[i] != k)
                        return false;
                }
                return true;
            };
            // 滑动窗口
            // for (int right = 0; right < s.length(); right++)
            // {
   
            //     alphaCount[s[right] - 'a']++;
            //     int left = right + 1 - m * k;
            //     if (left >= 0)
            //     {
   
            //         if (check())
            //             count++;
            //         alphaCount[s[left] - 'a']--;
            //     }
            // }
            for (int i = 0; i < m * k; i++)
                alphaCount[s[i] - 'a']++;
            if (check())
                count++;
            for (int right = m * k; right < s.length(); right++)
            {
   
                alphaCount[s[right] - 'a']++;
                alphaCount[s[right - m * k] - 'a']--;
                if (check())
                    count++;
            }
        }
        return count;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n∣Σ∣2),其中 n 为字符串 word 的长度,∣Σ∣ 为字符集合的大小,本题中字符均为小写英文字母,所以 ∣Σ∣=26。

空间复杂度:O(∣Σ∣)。忽略切片开销。

题目4:2954. 统计感冒序列的数目

思路

题解:组合数学题,附模板(Python/Java/C++/Go)

代码

/*
 * @lc app=leetcode.cn id=2954 lang=cpp
 *
 * [2954] 统计感冒序列的数目
 */

// @lc code=start

const static int MOD = 1e9 + 7;
const static int MX = 1e5;

long long q_pow(long long x, int n)
{
   
    long long res = 1;
    for (; n > 0; n /= 2)
    {
   
        if (n % 2)
        {
   
            res = res * x % MOD;
        }
        x = x * x % MOD;
    }
    return res;
}

// 组合数模板
long long fac[MX], inv_fac[MX];

auto init = []
{
   
    fac[0] = 1;
    for (int i = 1; i < MX; i++)
    {
   
        fac[i] = fac[i - 1] * i % MOD;
    }
    inv_fac[MX - 1] = q_pow(fac[MX - 1], MOD - 2);
    for (int i = MX - 1; i > 0; i--)
    {
   
        inv_fac[i - 1] = inv_fac[i] * i % MOD;
    }
    return 0;
}();

long long comb(int n, int k)
{
   
    return fac[n] * inv_fac[k] % MOD * inv_fac[n - k] % MOD;
}

class Solution
{
   
public:
    int numberOfSequence(int n, vector<int> &sick)
    {
   
        int m = sick.size();
        int total = n - m;
        long long ans = comb(total, sick[0]) * comb(total - sick[0], n - sick.back() - 1) % MOD;
        total -= sick[0] + n - sick.back() - 1;
        int e = 0;
        for (int i = 0; i < m - 1; i++)
        {
   
            int k = sick[i + 1] - sick[i] - 1;
            if (k)
            {
   
                e += k - 1;
                ans = ans * comb(total, k) % MOD;
                total -= k;
            }
        }
        return ans * q_pow(2, e) % MOD;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(m),其中 m 为数组 sick 的长度。预处理的时间忽略不计。

空间复杂度:O(1)。预处理的空间忽略不计。

相关推荐

  1. Leetcode 374 题解

    2024-01-04 11:58:02       60 阅读
  2. Leetcode 375,个人题解

    2024-01-04 11:58:02       47 阅读
  3. LeetCode377,个人题解

    2024-01-04 11:58:02       50 阅读
  4. LeetCode 379个人题解

    2024-01-04 11:58:02       59 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-04 11:58:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-04 11:58:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-04 11:58:02       82 阅读
  4. Python语言-面向对象

    2024-01-04 11:58:02       91 阅读

热门阅读

  1. HarmonyOS ArkTS 三方库的基本使用(十六)

    2024-01-04 11:58:02       55 阅读
  2. 学习的记录

    2024-01-04 11:58:02       49 阅读
  3. oj 1.9编程基础之顺序查找 09:直方图

    2024-01-04 11:58:02       61 阅读
  4. leetcode-两数之和

    2024-01-04 11:58:02       46 阅读
  5. linux 内核编译和日志

    2024-01-04 11:58:02       61 阅读
  6. es 简单集群搭建,版本8.6.2

    2024-01-04 11:58:02       48 阅读
  7. 用python合并文件夹中所有excel表

    2024-01-04 11:58:02       63 阅读
  8. Word与Excel对应的Python 函数库

    2024-01-04 11:58:02       59 阅读
  9. 数据库中的MVCC--多版本并发控制

    2024-01-04 11:58:02       50 阅读