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
的式子:
那我们将字符串\(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;
}
};