Q1 检查按位或是否存在尾随0
-
解题思路:
- 检查数组中有多少个奇数
- 如果有大于等于两个奇数,返回true,否则返回false
-
解题代码:
class Solution {
public:
bool hasTrailingZeros(vector<int>& nums) {
int cnt = 0;
for (auto num : nums) {
if (num & 1) {
continue;
}
cnt += 1;
if (cnt == 2) {
return true;
}
}
return false;
}
};
Q2 找出出现至少三次的最长特殊子字符串I
-
解题思路:
- 数据范围可以暴力
- 枚举每个子字符串,用哈希表统计各个特殊子字符串的出现次数
-
解题代码:
class Solution {
public:
int maximumLength(string s) {
int n = s.size();
unordered_map<string, int> um;
for (int i = 0; i < n; i++) {
int j = i+1;
string temp;
temp.push_back(s[i]);
um[temp] += 1;
while (j < n && s[j] == s[j-1]) {
temp += s[j];
um[temp] += 1;
j += 1;
}
}
int ans = -1;
for (auto &[s, cnt] : um) {
int len = s.size();
if (cnt >= 3 && len > ans) {
ans = len;
}
}
return ans;
}
};
Q3 找出出现至少三次的最长特殊子字符串II
-
解题思路:
-
分别记录字符串中各个字符连续出现的子串长度
-
枚举每种出现过的字符,分三种情况来讨论:
-
在最大的长度中,选择该长度-2的特殊子字符串
-
在最大和次大的长度中:
- 如果两个长度相等,选择该长度-1的特殊子字符串
- 如果两个长度不等,选择次大长度的特殊子字符串
-
在最大、次大和第三大长度中,选择第三大长度的特殊子字符串
-
-
答案为上述所有情况中的最大值
-
-
解题代码:
class Solution {
public:
int maximumLength(string s) {
int n = s.size();
vector<vector<int>> cnts(26);
for (int i = 0; i < n; i++) {
int j = i+1;
while (j < n && s[j] == s[j-1]) {
j += 1;
}
cnts[s[i]-'a'].push_back(j-i);
i = j-1;
}
int ans = -1;
for (int i = 0; i < 26; i++) {
auto &cnt = cnts[i];
sort(cnt.rbegin(), cnt.rend());
// 最长的拆三份
if (cnt.size() > 0 && cnt[0] >= 3) {
ans = max(ans, cnt[0] - 2);
}
if (cnt.size() >= 2) {
// 如果两个相等
if (cnt[0] == cnt[1] && cnt[0] != 1) {
ans = max(ans, cnt[0] - 1);
}
// 长的拆两份,短的不动
if (cnt[0] > cnt[1]) {
ans = max(ans, cnt[1]);
}
}
if (cnt.size() >= 3) {
ans = max(ans, cnt[2]);
}
}
return ans;
}
};
Q4 回文串重新排列查询
-
解题思路:
- 不能重新排列的区间,必须满足s[i] = t[i]
- 可以重新排列的区间,需要判断各字符出现次数是否一致
- 分情况讨论区间:
- 包含,直接判断大区间内各字符出现次数是否一致即可
- 相交但不包含, 分别计算s和t除去不能重新排列位置之外的字符出现次数,比较两个出现次数是否相同
- 不相交,分别判断各区间情况
-
解题代码:
class Solution {
public:
vector<bool> canMakePalindromeQueries(string s, vector<vector<int>>& queries) {
int n = s.size() / 2;
string t = s.substr(n, n);
reverse(t.begin(), t.end());
s = s.substr(0, n);
// 预处理前缀和
vector<vector<int>> sum_s(n+1, vector<int>(26, 0));
for (int i = 1; i <= n; i++) {
sum_s[i] = sum_s[i-1];
sum_s[i][s[i-1]-'a'] += 1;
}
vector<vector<int>> sum_t(n+1, vector<int>(26, 0));
for (int i = 1; i <= n; i++) {
sum_t[i] = sum_t[i-1];
sum_t[i][t[i-1]-'a'] += 1;
}
vector<int> eq(n+1, 0);
for (int i = 1; i <= n; i++) {
eq[i] = eq[i-1] + (s[i-1] == t[i-1]);
}
// 一些需要的函数
// 判断区间内字符出现次数是否相等
auto check_eq = [&](int l, int r) -> bool {
for (int i = 0; i < 26; i++) {
int temp1 = sum_s[r+1][i] - sum_s[l][i];
int temp2 = sum_t[r+1][i] - sum_t[l][i];
if (temp1 != temp2) {
return false;
}
}
return true;
};
// 返回差集
auto substract = [&](int l1, int r1, int l2, int r2, vector<vector<int>>& sum_s, vector<vector<int>>& sum_t) -> vector<int> {
vector<int> ans(26, 0);
for (int i = 0; i < 26; i++) {
int temp1 = sum_s[r1+1][i] - sum_s[l1][i];
int temp2 = sum_t[r2+1][i] - sum_t[l2][i];
if (temp1 < temp2) {
return {};
}
ans[i] = temp1 - temp2;
}
return ans;
};
auto func = [&](int l1, int r1, int l2, int r2, vector<vector<int>>& sum_s, vector<vector<int>>& sum_t) -> bool {
// l1 <= l2 的
// [0, l1-1], [max(r1, r2) + 1, n-1] 需要完全相同
if (eq[l1] - eq[0] != l1 || eq[n] - eq[max(r1, r2)+1] != n - 1 -max(r1, r2)) {
return false;
}
if (r1 >= r2) {
// 包含
if (!check_eq(l1, r1)) {
return false;
}
} else if (r1 < l2) {
// 不相交 [r1+1, l2-1]也是不可重新排列的区间
if (!check_eq(l1, r1) || !check_eq(l2, r2) || eq[l2] - eq[r1+1] != l2-r1-1) {
return false;
}
} else {
// 相交但不包含
auto s1 = substract(l1, r1, l1, l2-1, sum_s, sum_t); // sum_s[l1, r1] - sum_t[l1, l2-1]
auto s2 = substract(l2, r2, r1+1, r2, sum_t, sum_s); // sum_t[l2, r2] - sum_s[r1+1, r2]
if (s1.empty() || s2.empty()) {
return false;
}
for (int i = 0; i < 26; i++) {
if (s1[i] != s2[i]) {
return false;
}
}
}
return true;
};
vector<bool> ans;
for (auto &query : queries) {
int l1 = query[0], r1 = query[1], l2 = n * 2 - 1 - query[3], r2 = n * 2 - 1 - query[2];
if (l2 < l1) {
ans.push_back(func(l2, r2, l1, r1, sum_t, sum_s));
} else {
ans.push_back(func(l1, r1, l2, r2, sum_s, sum_t));
}
}
return ans;
}
};