LeetCode第 278 场周赛题解

5993. 将找到的值乘以 2

题目描述:给你一个数组\(nums\)和一个整数\(x\),若\(x\)在数组中就将\(x\)乘以\(2\),否则返回\(x\)的值。

思路:使用map存储数组中的值,然后根据题意模拟即可

时间复杂度:\(O(nlogn)\)

参考代码:

class Solution {
public:
    int findFinalValue(vector<int>& nums, int original) {
        map<int , int>mp;
        for(auto num : nums) mp[num] = 1;
        while(mp[original]) original <<= 1;
        return original;
    }
};

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

题目描述:给你一个只有01的数组,将数组分成两部分,左边部分的分数为0的个数,右边部分为1的个数,分组得分为左右部分的分数之和,求所有使得分组得分最高的下标。

思路:比较简单的dp,根据题意模拟即可。

时间复杂:\(O(n)\)

参考代码:

class Solution {
public:
    vector<int> maxScoreIndices(vector<int>& nums) {
        int n = nums.size();
        vector<int>f(n + 1 , 0) , g(n + 2 , 0);
        for(int i = 1 ; i <= n ; ++i){
            f[i] = nums[i - 1] == 0;
            f[i] += f[i - 1];
        }
        for(int i = n ; i >= 1 ; --i){
            g[i] = nums[i - 1] == 1;
            g[i] += g[i + 1];
        }
        vector<int>res;
        int max = 0;
        for(int i = 1 ; i <= n + 1; ++i){
            if(f[i - 1] + g[i] < max) continue;
            if(f[i - 1] + g[i] == max) res.push_back(i - 1);
            else{
                max = f[i - 1] + g[i];
                res.clear();
                res.push_back(i - 1);
            }
        }
        return res;
    }
};

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

题目描述:给定长度为\(n\)的字符串\(s\),求其长度为\(k\)的所有子串中满足等式:

\[\sum\limits_{i = 1}^{k} t_i \times p^{i - 1} \% mod = hashValue \]

且出现最早的子串。其中\(t\)表示长度为\(k\)的子串,字符\(t_i\)的整数值为\(t_i - 'a' + 1\)。

思路:

赛时思路为:考虑到下列等式:

\[s_i*p^0 + s_{i + 1}*p^1 + ..+ s_{i + k - 1}*p^{k - 1}\\ = \frac{s_i*p^{i} + s_{i + 1}*p^{i + 1} + ..+ s_{i + k - 1}*p^{i + k - 1}}{b^{i}} \]

那么我们可以将\(b^i *hashValue\) 作为等式的右边,在取模的情况下检验左右两边是否相等。但将分母乘过去再取模可能会存在hash冲突,比较保险的做法是求\(b^i\)的逆元,但其逆元可能不存在,我当时的做法时在检验到相等的时候,再代入检验一遍,代码如下:

class Solution {
public:
    string subStrHash(string s, int power, int mod, int k, int hashValue) {
        int n = s.size();
        vector<int>base(n + 1 , 0);
        base[0] = 1;
        vector<int>has(n + 1 , 0);
        for(int i = 1 ; i <= n ; ++i){
            has[i] = has[i - 1] + 1ll *(s[i - 1] - 'a' + 1) * base[i - 1] % mod;
            has[i] %= mod;
            base[i] = 1ll * base[i - 1] * power % mod;
        }
        //for(auto ha : has) cout << ha <<" " ;
        //cout << endl;
        for(int i = k ; i <= n; ++i){
            int dx = ((has[i] - has[i - k]) % mod + mod) % mod;
            int dy = 1ll * hashValue * base[i - k] % mod;
            if(dx == dy) {
                int tmp = 0, b = 1;
                for(int j = i - k ; j < i ; ++j){
                    tmp = tmp + 1ll * (s[j] - 'a' + 1) * b % mod;
                    tmp %= mod;
                    b = 1ll * b * power % mod;
                }
                if(tmp == hashValue) return s.substr(i - k , k);
            }
        }
        return "";
    }
};

上述代码是可以被卡掉的。

字符串Hash操作可以参考此处

后来考虑到字符串hash的式子:

\[hash = \sum\limits_{i = 1}^{n} s_i * p^{n - i} \]

那我们将字符串\(s\)转置一下,那么上式就变成了

\[hash = \sum\limits_{i = 1}^{n} t_i * p^{i - 1}\;\;t_i = s_{n - i + 1} \]

跟题目所求式子相同,故可以将字符串\(s\)转置,然后预处理其字符串hash值,然后根据该值找到相对应的答案。

时间复杂度:\(O(n)\)

参考代码:

class Solution {
public:
    string subStrHash(string s, int power, int mod, int k, int hashValue) {
        reverse(s.begin() , s.end());
        int n = s.size();
        vector<int>base(n + 1 , 0),has(n + 1 , 0);
        base[0] = 1;
        for(int i = 1 ; i <= n ; ++i){
            has[i] = (1ll * has[i - 1] * power % mod + s[i - 1] - 'a' + 1) % mod;
            base[i] = 1ll * base[i - 1] * power % mod;
        }
        auto getHash = [&](int lr , int rs)->int{
            return ((has[rs] - 1ll * has[lr - 1] * base[rs - lr + 1] % mod)% mod + mod) % mod;
        };
        int idx = 0;
        for(int i = 1 ; i <= n - k + 1 ; ++i){
            if(getHash(i , i + k - 1) == hashValue) idx = i;
        }
        string res = s.substr(idx - 1 , k);
        reverse(res.begin() , res.end());
        return res;
    }
};

5995. 字符串分组

题目描述:自己看题目吧,虽然题目描述读起来怪怪的。

思路:考虑到每个字符串中的每种字符最多出现一次,所以考虑将字符串使用数组表示,例如字符串ab,可以用3表示。然后每一个字符串当做一个点,我们根据题目的规则去枚举其能产生的点,若枚举到的点存在,那么就将这两个点所对应的连通块合并,故其中需要使用并查集。最后的答案就是连通块的数量和最大的连通块中点的数量。注意到可能存在相同的字符串,需要特判。

时间复杂度:\(O(26^2n)\) \(n\)为字符串的数量。

参考代码:

class Solution {
public:
    vector<int> groupStrings(vector<string>& words) {
        int n = words.size();
        vector<int>p(n + 1 , 0) , cnt(n + 1 , 0);
        map<int , int>mp;
        for(int i = 1 ; i <= n ; ++i){
            p[i] = i;
            cnt[i] = 1;
        }
        auto find = [&] (auto find , int x)->int{
            if(x != p[x]) p[x] = find(find , p[x]);
            return p[x];
        };
        auto cal = [&](string& s)->int{
            int ans = 0;
            for(auto& c : s) ans |= 1 << (c - 'a');
            return ans;
        };
        auto solve = [&](int x, int idx)->void{
            if(mp.count(x) != 0){
                int u = find(find , mp[x]) , v = find(find , idx);
                p[u] = v;
                cnt[v] += cnt[u];
                return ;
            }
            mp[x] = idx;
            for(int i = 0 ; i < 26 ; ++i){
                int dy = x ^ (1 << i);
                if(mp.count(dy) == 0) continue;
                int u = find(find, mp[dy]) , v = find(find , idx);
                if(u == v) continue;
                p[u] = v;
                cnt[v] += cnt[u];
            }
            for(int i = 0 ; i < 26 ; ++i){
                if(((x >> i) & 1) == 0) continue;
                for(int j = 0 ; j < 26 ; ++j){
                    if((x >> j) & 1) continue;
                    int dy = x ^ (1 << i) ^ (1 << j);
                    if(mp.count(dy) == 0) continue;
                    int u = find(find , mp[dy]) , v = find(find , idx);
                    if(u == v) continue;
                    p[u] = v;
                    cnt[v] += cnt[u];
                }
            }
            return ;
        };
        for(int i = 1 ; i <= n ; ++i){
            int dx = cal(words[i - 1]);
            solve(dx , i);
        }
        vector<int>res(2 , 0);
        for(int i = 1 ; i <= n ; ++i){
            res[0] += p[i] == i;
            res[1] = max(res[1] , cnt[i]);
        }
        return res;
    }
};
上一篇:scanf,sscanf高级用法


下一篇:[题解]智乃买瓜