Leetcode 第 382 场周赛题解

Leetcode 第 382 场周赛题解

  • Leetcode 第 382 场周赛题解
    • 题目1:3019. 按键变更的次数
      • 思路
      • 代码
      • 复杂度分析
    • 题目2:3020. 子集中元素的最大数量
      • 思路
      • 代码
      • 复杂度分析
    • 题目3:3021. Alice 和 Bob 玩鲜花游戏
      • 思路
      • 代码
      • 复杂度分析
    • 题目4:3022. 给定操作次数内使剩余元素的或值最小
      • 思路
      • 代码
      • 复杂度分析

Leetcode 第 382 场周赛题解

题目1:3019. 按键变更的次数

思路

双指针。

给你一个下标从 0 开始的字符串 s ,该字符串由用户输入。按键变更的定义是:使用与上次使用的按键不同的键。例如 s = “ab” 表示按键变更一次,而 s = “bBBb” 不存在按键变更。

返回用户输入过程中按键变更的次数。

注意:shift 或 caps lock 等修饰键不计入按键变更,也就是说,如果用户先输入字母 ‘a’ 然后输入字母 ‘A’ ,不算作按键变更。

使用双指针指向字符串中两个相邻的字符 s[i] 和 s[j](0<=i

最后返回按键变更计数。

代码

/*
 * @lc app=leetcode.cn id=100215 lang=cpp
 *
 * [100215] 按键变更的次数
 */

// @lc code=start
class Solution
{
public:
    int countKeyChanges(string s)
    {
        // 特判
        if (s.empty())
            return 0;

        int n = s.length();
        int count = 0;
        for (int i = 0, j = 1; i < n && j < n; i++, j++)
            if (tolower(s[i]) != tolower(s[j]))
                count++;
        return count;
    }
};
// @lc code=end

复杂度分析

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

空间复杂度:O(1)。

题目2:3020. 子集中元素的最大数量

思路

用一个哈希表统计数组 nums 中的元素及其出现次数。

暴力枚举数组中的数,作为 x,然后不断看 x2,x4,⋯ 在数组中的个数。直到个数不足 2 个为止,退出循环。

注意模式的正中间的数字只取一个。如果最后 x 有一个,那么个数加一,否则个数减一。

注意特判 x=1 的情况。

代码

/*
 * @lc app=leetcode.cn id=100206 lang=cpp
 *
 * [100206] 子集中元素的最大数量
 */

// @lc code=start
class Solution
{
public:
    int maximumLength(vector<int> &nums)
    {
        // 特判
        if (nums.empty())
            return 0;

        unordered_map<long long, int> cnt;
        for (int &num : nums)
            cnt[num]++;

        // 特判 x=1 的情况
        int ans = cnt[1] - (cnt[1] % 2 == 0);
        cnt.erase(1);

        for (auto &[num, _] : cnt)
        {
            int res = 0;
            long long x;
            for (x = num; cnt.contains(x) && cnt[x] > 1; x *= x)
                res += 2;
            if (cnt.contains(x))
                res++;
            else
                res--;
            ans = max(ans, res);
        }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(nloglogU),其中 n 为数组 nums 的长度,U=max⁡(nums)。

空间复杂度:O(n)。

题目3:3021. Alice 和 Bob 玩鲜花游戏

思路

数学。

Alice 和 Bob 在一个长满鲜花的环形草地玩一个回合制游戏。环形的草地上有一些鲜花,Alice 到 Bob 之间顺时针有 x 朵鲜花,逆时针有 y 朵鲜花。

游戏过程如下:

  1. Alice 先行动。
  2. 每一次行动中,当前玩家必须选择顺时针或者逆时针,然后在这个方向上摘一朵鲜花。
  3. 一次行动结束后,如果所有鲜花都被摘完了,那么当前玩家抓住对手并赢得游戏的胜利。

给你两个整数 n 和 m ,你的任务是求出满足以下条件的所有 (x, y) 对:

  • 按照上述规则,Alice 必须赢得游戏。
  • Alice 顺时针方向上的鲜花数目 x 必须在区间 [1,n] 之间。
  • Alice 逆时针方向上的鲜花数目 y 必须在区间 [1,m] 之间。

请你返回满足题目描述的数对 (x, y) 的数目。

显然,因为是 Alice 先行动,当 x+y 为奇数时,Alice 会摘完最后一朵鲜花,抓住对手并赢得游戏的胜利。

x+y 为奇数有两种情况:

  1. x 为奇数,y 为偶数
  2. x 为偶数,y 为奇数

在 [1,n] 区间内,有 n/2 个偶数,(n+1)/2 个奇数。

所以最终答案为 (n / 2) * ((m + 1) / 2) + ((n + 1) / 2) * (m / 2)。

更进一步,把这道题想象成一个网格。

Leetcode 第 382 场周赛题解_第1张图片

枚举一下 x 和 y 的奇偶性,得出答案为 n*m/2。

代码

/*
 * @lc app=leetcode.cn id=3021 lang=cpp
 *
 * [3021] Alice 和 Bob 玩鲜花游戏
 */

// @lc code=start

// 数学

class Solution
{
public:
    long long flowerGame(int n, int m)
    {
        return (long long)n * m / 2;
    }
};

// Time Limit Exceeded

// class Solution
// {
// public:
//     long long flowerGame(int n, int m)
//     {
//         long long count = 0;
//         for (int x = 1; x <= n; x++)
//             for (int y = 1; y <= m; y++)
//                 if ((x + y) ^ 0x1)
//                     count++;
//         return count / 2;
//     }
// };

// class Solution
// {
// public:
//     long long flowerGame(int n, int m)
//     {
//         return (long long)(n / 2) * ((m + 1) / 2) +
//                (long long)((n + 1) / 2) * (m / 2);
//     }
// };
// @lc code=end

复杂度分析

时间复杂度:O(1)。

空间复杂度:O(1)。

题目4:3022. 给定操作次数内使剩余元素的或值最小

思路

位运算 + 试填法。

题解:试填法(Python/Java/C++/Go)

代码

/*
 * @lc app=leetcode.cn id=3022 lang=cpp
 *
 * [3022] 给定操作次数内使剩余元素的或值最小
 */

// @lc code=start
class Solution
{
public:
    int minOrAfterOperations(vector<int> &nums, int k)
    {
        int ans = 0, mask = 0;
        // 从高位到低位一次枚举
        for (int b = 29; b >= 0; b--)
        {
            mask |= 1 << b;
            int cnt = 0;
            // -1 在二进制下全为 1,所以可以省去特判每一段第一个数
            int and_res = -1;
            for (int &x : nums)
            {
                and_res &= x & mask;
                if (and_res)
                {
                    // 合并 x,操作次数加一
                    cnt++;
                }
                else
                {
                    // 准备合并下一段,省去特判每一段的第一个数
                    and_res = -1;
                }
            }
            if (cnt > k)
            {
                ans |= 1 << b; // 答案的这个比特位必须是 1
                // 后面不考虑这个比特位,这一位一定为 1,消除这一位的影响
                mask ^= 1 << b;
            }
        }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(nlog⁡U),其中 n 为数组 nums 的长度,U=max⁡(nums)。

空间复杂度:O(1)。

你可能感兴趣的:(Every,day,a,LeetCode,leetcode,C++,数据结构与算法,双指针,哈希,数学,位运算)