感谢又给一次AK的机会,AK传送门
题目
思路
代码
class Solution {
public:
bool strongPasswordCheckerII(string p) {
int n = p.size();
if(n < 8) return false;
string s = "!@#$%^&*()-+";
bool o1 = true, o2 = true, o3 = true, o4 = true, o5 = true;
for (int i = 0; i < n; i++) {
if(p[i] <= 'z' && p[i] >= 'a') o1 = false;
if(p[i] <= 'Z' && p[i] >= 'A') o2 = false;
if(p[i] <= '9' && p[i] >= '0') o3 = false;
for (int j = 0; j < s.size(); j++) if(s[j] == p[i]) o4 = false;
if(i && p[i] == p[i - 1]) o5 = false;
}
return !o1 && !o2 && !o3 && !o4 && o5;
}
};
题目
思路
计算 s p e l l s [ i ] ∗ p o t i o n s [ j ] > = s u c c e s s {spells[i] * potions[j] >= success} spells[i]∗potions[j]>=success ,每个 i {i} i 有多少个 j {j} j 满足。
转化为找到 s p e l l s [ i ] > = s u c c e s s / p o t i o n s [ j ] spells[i] >= success \ / \ potions[j] spells[i]>=success / potions[j],有多少个 j {j} j 满足。
那么此时我们可以新开数组 a [ j ] a[j] a[j] 用以表示 s u c c e s s / p o t i o n s [ j ] success \ / \ potions[j] success / potions[j]
由于在此是大于等于才满足条件(也即 a [ j ] < = s p e l l s [ i ] a[j]<=spells[i] a[j]<=spells[i]),那么我们将 a a a 数组存储上取整的值: ( s u c c e s s − 1 ) / p o t i o n s [ j ] + 1 (success-1) \ / \ potions[j] + 1 (success−1) / potions[j]+1。
相当于是找到 a [ j ] < s p e l l s [ i ] a[j] < spells[i] a[j]<spells[i] 的 j j j 的个数,此时我们将 a a a 数组升序排列,可以用二分查找临界位置。
代码
class Solution {
public:
vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, long long success) {
vector<int> res;
vector<long long> a;
for (int i = 0; i < potions.size(); i++) {
a.push_back(1ll * (success - 1) / potions[i] + 1);
}
sort(a.begin(), a.end());
for (int i = 0; i < spells.size(); i++) {
int id = upper_bound(a.begin(), a.end(), spells[i]) - a.begin();
res.push_back(id);
}
return res;
}
};
题目
思路
其实我们看数据发现, 5000 5000 5000 的字符串长度 ,大概 n 2 n^2 n2 也就是 3 e 7 3e7 3e7,加上中间字符串的匹配操作,卡个极限时间能过。
细节详见代码部分
代码
class Solution {
public:
map<char, map<char, bool>> mp;
bool matchReplacement(string s, string sub, vector<vector<char>>& mappings) {
int n = s.size(), m = sub.size();
if(m > n) return false;
for (int i = 0; i < mappings.size(); i++) {
char a = mappings[i][0], b = mappings[i][1];
mp[a][b] = true;
}
for (int i = 0; i < n - m + 1; i++) {
string pre = s.substr(i, m);
bool o = true;
for (int j = 0; j < m; j++) {
if(!mp[sub[j]][pre[j]] && sub[j] != pre[j]) o = false;
if(!o) break;
}
if(o) return true;
}
return false;
}
};
s u f suf suf 数组存储最终每个字符所有能转移到的状态
最终结果就是取 s u b sub sub 中每个字符状态的并集
位运算加速,代码如下:
class Solution {
public:
static const int N = 5010;
bitset<N> res, pre[128], suf[128];
bool matchReplacement(string s, string sub, vector<vector<char>>& mappings) {
for (int i = 0; i < 128; i++) pre[i].reset();
for (int i = 0; i < s.size(); i++) pre[s[i]].set(i);
for (int i = 0; i < 128; i++) suf[i] = pre[i];
for (auto &mp: mappings) suf[mp[0]] |= pre[mp[1]];
res.set();
for (int i = 0; i < sub.size(); i++) res &= suf[sub[i]] >> i;
return res.count();
}
};
思路
由此我们可以想到有双指针来解决,(应该可以吧hhh
那么如何计算上每个状态的贡献呢?
误:一开始我对贡献计算是区间 l , r l, r l,r 之间所有区间数,显然这样会有大量的重复区间的计算,读者可自行思考。
代码
class Solution {
public:
#define ll long long
long long countSubarrays(vector<int>& nums, long long k) {
int r = 0, n = nums.size();
ll now = 0, len = 0, res = 0;
for (int i = 0; i < n; i++) {
while(r < n && ((now + nums[r])) * (len + 1) < k) {
now += nums[r];
len ++;
res += (r - i + 1);
r++;
}
now -= nums[i];
len--;
}
return res;
}
};