LeetCode周赛总结——第 278 场周赛

140 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

5993. 将找到的值乘以 2

题目

给你一个整数数组 nums ,另给你一个整数 original ,这是需要在 nums 中搜索的第一个数字。

接下来,你需要按下述步骤操作:

如果在 nums 中找到 original ,将 original 乘以 2 ,得到新 original(即,令 original = 2 * original)。 否则,停止这一过程。 只要能在数组中找到新 original ,就对新 original 继续 重复 这一过程。 返回 original 的 最终 值。

示例 1:

输入:nums = [5,3,6,1,12], original = 3
输出:24
解释: 
- 3 能在 nums 中找到。3 * 2 = 6 。
- 6 能在 nums 中找到。6 * 2 = 12 。
- 12 能在 nums 中找到。12 * 2 = 24 。
- 24 不能在 nums 中找到。因此,返回 24 。

示例 2:

输入:nums = [2,7,9], original = 4
输出:4
解释:
- 4 不能在 nums 中找到。因此,返回 4 。

提示:

1 <= nums.length <= 1000
1 <= nums[i], original <= 1000

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/ke…

分析

将nums中的所有数加入到集合中,再查看original,如果在集合里original乘2,直到不在集合里为止

代码

class Solution {
public:
    int findFinalValue(vector<int>& nums, int original) {
        set<int> s;
        for(int i=0; i < nums.size(); i++){
            s.insert(nums[i]);
        }
        while(s.count(original)){
            original *= 2;
        }
        return original;
    }
};

5981. 分组得分最高的所有下标

题目

给你一个下标从 0 开始的二进制数组 nums ,数组长度为 n 。nums 可以按下标 i( 0 <= i <= n )拆分成两个数组(可能为空):numsleft 和 numsright 。

numsleft 包含 nums 中从下标 0 到 i - 1 的所有元素(包括 0 和 i - 1 ),而 numsright 包含 nums 中从下标 i 到 n - 1 的所有元素(包括 i 和 n - 1 )。 如果 i == 0 ,numsleft 为 空 ,而 numsright 将包含 nums 中的所有元素。 如果 i == n ,numsleft 将包含 nums 中的所有元素,而 numsright 为 空 。 下标 i 的 分组得分 为 numsleft 中 0 的个数和 numsright 中 1 的个数之 和 。

返回 分组得分 最高 的 所有不同下标 。你可以按 任意顺序 返回答案。

示例 1:

输入:nums = [0,0,1,0]
输出:[2,4]
解释:按下标分组
- 0 :numsleft 为 [] 。numsright 为 [0,0,1,0] 。得分为 0 + 1 = 1 。
- 1 :numsleft 为 [0] 。numsright 为 [0,1,0] 。得分为 1 + 1 = 2 。
- 2 :numsleft 为 [0,0] 。numsright 为 [1,0] 。得分为 2 + 1 = 3 。
- 3 :numsleft 为 [0,0,1] 。numsright 为 [0] 。得分为 2 + 0 = 2 。
- 4 :numsleft 为 [0,0,1,0] 。numsright 为 [] 。得分为 3 + 0 = 3 。
下标 24 都可以得到最高的分组得分 3 。
注意,答案 [4,2] 也被视为正确答案。

示例 2:

输入:nums = [0,0,0]
输出:[3]
解释:按下标分组
- 0 :numsleft 为 [] 。numsright 为 [0,0,0] 。得分为 0 + 0 = 0 。
- 1 :numsleft 为 [0] 。numsright 为 [0,0] 。得分为 1 + 0 = 1 。
- 2 :numsleft 为 [0,0] 。numsright 为 [0] 。得分为 2 + 0 = 2 。
- 3 :numsleft 为 [0,0,0] 。numsright 为 [] 。得分为 3 + 0 = 3 。
只有下标 3 可以得到最高的分组得分 3

示例 3:

输入:nums = [1,1]
输出:[0]
解释:按下标分组
- 0 :numsleft 为 [] 。numsright 为 [1,1] 。得分为 0 + 2 = 2 。
- 1 :numsleft 为 [1] 。numsright 为 [1] 。得分为 0 + 1 = 1 。
- 2 :numsleft 为 [1,1] 。numsright 为 [] 。得分

为 0 + 0 = 0 。 只有下标 0 可以得到最高的分组得分 2 。

提示:

n == nums.length
1 <= n <= 105
nums[i] 为 01
通过次数2,849提交次数4

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/al…

分析

left[i]为从前i-1位0的个数,right[i]是从i开始到最后1的个数,用两个循环即可求出以i为分割时left和right对应的值,遍历求和可得他们的和

代码

class Solution {
public:
    int left[100005];
    int right[100005];
    int sumn[100005];
    vector<int> maxScoreIndices(vector<int>& nums) {
        int cnt=0;
        for(int i=0; i <= nums.size(); i++){
            left[i]=cnt;
            if(i < nums.size() && nums[i] == 0){
                cnt++;
            }
            
        }
        cnt = 0;
        right[nums.size()] = 0;
        for(int i=nums.size(); i >= 0; i--){
            if(i < nums.size() && i >= 0 && nums[i] == 1){
                cnt++;
            }
            right[i]=cnt; 
        }
        for(int i=0; i <= nums.size(); i++){
            sumn[i] = left[i] + right[i];
            //cout<<i<<" "<<left[i]<<" "<<right[i]<<endl;
            cnt = max(cnt, sumn[i]);
        }
        vector<int> ans;
        for(int i=0; i <= nums.size(); i++){
            if(sumn[i] == cnt){
                ans.push_back(i);
            }
        }
        return ans;
    }
};

5994. 查找给定哈希值的子串

题目

给定整数 p 和 m ,一个长度为 k 且下标从 0 开始的字符串 s 的哈希值按照如下函数计算:

hash(s, p, m) = (val(s[0]) * p0 + val(s[1]) * p1 + ... + val(s[k-1]) * pk-1) mod m. 其中 val(s[i]) 表示 s[i] 在字母表中的下标,从 val('a') = 1 到 val('z') = 26 。

给你一个字符串 s 和整数 power,modulo,k 和 hashValue 。请你返回 s 中 第一个 长度为 k 的 子串 sub ,满足 hash(sub, power, modulo) == hashValue 。

测试数据保证一定 存在 至少一个这样的子串。

子串 定义为一个字符串中连续非空字符组成的序列。

示例 1:

输入:s = "leetcode", power = 7, modulo = 20, k = 2, hashValue = 0
输出:"ee"
解释:"ee" 的哈希值为 hash("ee", 7, 20) = (5 * 1 + 5 * 7) mod 20 = 40 mod 20 = 0"ee" 是长度为 2 的第一个哈希值为 0 的子串,所以我们返回 "ee"

示例 2:

输入:s = "fbxzaad", power = 31, modulo = 100, k = 3, hashValue = 32
输出:"fbx"
解释:"fbx" 的哈希值为 hash("fbx", 31, 100) = (6 * 1 + 2 * 31 + 24 * 312) mod 100 = 23132 mod 100 = 32"bxz" 的哈希值为 hash("bxz", 31, 100) = (2 * 1 + 24 * 31 + 26 * 312) mod 100 = 25732 mod 100 = 32"fbx" 是长度为 3 的第一个哈希值为 32 的子串,所以我们返回 "fbx" 。
注意,"bxz" 的哈希值也为 32 ,但是它在字符串中比 "fbx" 更晚出现。

提示:

1 <= k <= s.length <= 2 * 104
1 <= power, modulo <= 109
0 <= hashValue < modulo
s 只包含小写英文字母。
测试数据保证一定 存在 满足条件的子串。

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/fi…

分析

由于在运算过程中会大量的出现幂运算,刚开始想到的是快速幂,但是快速幂还不够快,可以使用一种更为返璞归真的方式,通过打表记录所有的幂

代码

class Solution {
public:
    string subStrHash(string s, int power, int modulo, int k, int hashValue) {
        int n[s.size()];
        string ans;
        n[0]=1;
        for(int i=1; i < s.size(); i++){
            n[i] = (long long)n[i-1] * power % modulo;
        }
        for(int i=0; i < s.size(); i++){
            int h=0;
            for(int j=i; j < i+k; j++){
                h += (long long)(s[j] - 'a' + 1) % modulo * n[j-i] % modulo; 
                h %= modulo;
            }
            if(h == hashValue){
                return s.substr(i, k);
            }
        }
        return ans;
    }
};

5995. 字符串分组

题目

给你一个下标从 0 开始的字符串数组 words 。每个字符串都只包含 小写英文字母 。words 中任意一个子串中,每个字母都至多只出现一次。

如果通过以下操作之一,我们可以从 s1 的字母集合得到 s2 的字母集合,那么我们称这两个字符串为 关联的 :

往 s1 的字母集合中添加一个字母。 从 s1 的字母集合中删去一个字母。 将 s1 中的一个字母替换成另外任意一个字母(也可以替换为这个字母本身)。 数组 words 可以分为一个或者多个无交集的 组 。一个字符串与一个组如果满足以下 任一 条件,它就属于这个组:

它与组内 至少 一个其他字符串关联。 它是这个组中 唯一 的字符串。 注意,你需要确保分好组后,一个组内的任一字符串与其他组的字符串都不关联。可以证明在这个条件下,分组方案是唯一的。

请你返回一个长度为 2 的数组 ans :

ans[0] 是 words 分组后的 总组数 。 ans[1] 是字符串数目最多的组所包含的字符串数目。

示例 1:

输入:words = ["a","b","ab","cde"] 输出:[2,3] 解释:

  • words[0] 可以得到 words[1] (将 'a' 替换为 'b')和 words[2] (添加 'b')。所以 words[0] 与 words[1] 和 words[2] 关联。
  • words[1] 可以得到 words[0] (将 'b' 替换为 'a')和 words[2] (添加 'a')。所以 words[1] 与 words[0] 和 words[2] 关联。
  • words[2] 可以得到 words[0] (删去 'b')和 words[1] (删去 'a')。所以 words[2] 与 words[0] 和 words[1] 关联。
  • words[3] 与 words 中其他字符串都不关联。 所以,words 可以分成 2 个组 ["a","b","ab"] 和 ["cde"] 。最大的组大小为 3 。

示例 2:

输入:words = ["a","ab","abc"] 输出:[1,3] 解释:

  • words[0] 与 words[1] 关联。
  • words[1] 与 words[0] 和 words[2] 关联。
  • words[2] 与 words[1] 关联。 由于所有字符串与其他字符串都关联,所以它们全部在同一个组内。 所以最大的组大小为 3 。

提示:

1 <= words.length <= 2 * 104 1 <= words[i].length <= 26 words[i] 只包含小写英文字母。 words[i] 中每个字母最多只出现一次。

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/gr…

分析

将字母转换成二进制格式存储,对于字母进行二进制遍历+广度优先搜索即可

代码 由于个人写的比较杂乱,这里附上官方简洁明了的题解 题解原地址

class Solution {
public:
    vector<int> groupStrings(vector<string>& words) {
        // 使用哈希映射统计每一个二进制表示出现的次数
        unordered_map<int, int> wordmasks;
        for (const string& word: words) {
            int mask = 0;
            for (char ch: word) {
                mask |= (1 << (ch - 'a'));
            }
            ++wordmasks[mask];
        }
        
        // 辅助函数,用来得到 mask 的所有可能的相邻节点
        auto get_adjacent = [](int mask) -> vector<int> {
            vector<int> adj;
            // 将一个 0 变成 1,或将一个 1 变成 0
            for (int i = 0; i < 26; ++i) {
                adj.push_back(mask ^ (1 << i));
            }
            // 将一个 0 变成 1,且将一个 1 变成 0
            for (int i = 0; i < 26; ++i) {
                if (mask & (1 << i)) {
                    for (int j = 0; j < 26; ++j) {
                        if (!(mask & (1 << j))) {
                            adj.push_back(mask ^ (1 << i) ^ (1 << j));
                        }
                    }
                }
            }
            return adj;
        };
        
        unordered_set<int> used;
        int best = 0, cnt = 0;
        for (const auto& [mask, occ]: wordmasks) {
            if (used.count(mask)) {
                continue;
            }
            // 从一个未搜索过的节点开始进行广度优先搜索,并求出对应连通分量的大小
            queue<int> q;
            q.push(mask);
            used.insert(mask);
            // total 记录联通分量的大小
            int total = occ;
            while (!q.empty()) {
                int u = q.front();
                q.pop();
                for (int v: get_adjacent(u)) {
                    if (wordmasks.count(v) && !used.count(v)) {
                        q.push(v);
                        used.insert(v);
                        total += wordmasks[v];
                    }
                }
            }
            best = max(best, total);
            ++cnt;
        }
            
        return {cnt, best};
    }
};