周赛链接:
https://leetcode.cn/contest/biweekly-contest-88/
A. 2423. 删除字符使频率相同
给你一个下标从 0 开始的字符串 word ,字符串只包含小写英文字母。你需要选择 一个 下标并 删除 下标处的字符,使得 word 中剩余每个字母出现 频率 相同。
如果删除一个字母后,word 中剩余所有字母的出现频率都相同,那么返回 true ,否则返回 false 。
注意:
字母 x 的 频率 是这个字母在字符串中出现的次数。
你 必须 恰好删除一个字母,不能一个字母都不删除。
对于这个坑题,真的不应该面相用例编程,交了2发WA,就应该直接暴力解题。
AC代码:
class Solution {
public:
bool equalFrequency(string word) {
vector<int> s(26, 0);
for (auto c : word)
s[c - 'a'] ++;
map<int, int> m;
for (auto c : s)
{
if (c == 0) continue;
m[c] ++;
}
if (m.size() == 2) {
int maxn = -1, cnt;
for (auto it = m.begin(); it != m.end(); it ++)
{
if (maxn == -1) maxn = it -> first, cnt = it -> second;
else if ((it -> second == 1 || cnt == 1) && abs(it -> first - maxn) == 1) return true;
}
} else if (m.size() == 1) {
if (m.begin()->first == 1 || m.begin()->second == 1) return true;
}
return false;
}
};
B. 2424. 最长上传前缀
题目描述:
给你一个 n 个视频的上传序列,每个视频编号为 1 到 n 之间的 不同 数字,你需要依次将这些视频上传到服务器。请你实现一个数据结构,在上传的过程中计算 最长上传前缀 。如果 闭区间 1 到 i 之间的视频全部都已经被上传到服务器,那么我们称 i 是上传前缀。最长上传前缀指的是符合定义的 i 中的 最大值 。
请你实现 LUPrefix 类:
LUPrefix(int n) 初始化一个 n 个视频的流对象。
void upload(int video) 上传 video 到服务器。
int longest() 返回上述定义的 最长上传前缀 的长度。
数据结构设计题,video
的范围是1~1e5
,所以用数组模拟哈希就可以,不需要用unordered_map
。
AC代码:
class LUPrefix {
public:
int maxn = 0;
unordered_map<int, int> m;
LUPrefix(int n) {
m.clear();
maxn = 0;
}
void upload(int video) {
m[video] = 1;
if (maxn + 1 == video)
{
int t = video;
while(m.count(t) == 1)
{
t ++;
}
maxn = t - 1;
}
}
int longest() {
return maxn;
}
};
/**
* Your LUPrefix object will be instantiated and called as such:
* LUPrefix* obj = new LUPrefix(n);
* obj->upload(video);
* int param_2 = obj->longest();
*/
C. 2425. 所有数对的异或和
题目描述:
给你两个下标从 0 开始的数组 nums1 和 nums2 ,两个数组都只包含非负整数。请你求出另外一个数组 nums3 ,包含 nums1 和 nums2 中 所有数对 的异或和(nums1 中每个整数都跟 nums2 中每个整数 恰好 匹配一次)。
请你返回 nums3 中所有整数的 异或和 。
这道题要到异或的两个性质:
- 交换律
a ^ a = 0
,0 ^ a = a
举例说明:
nums1 = [a, b, c]
nums2 = [d, e]
nums3 = [a ^ d, a ^ e, b ^ d, b ^ e, c ^ d, c ^ e]
(a ^ d) ^ (a ^ e) ^ (b ^ d) ^ (b ^ e) ^ (c ^ d) ^ (c ^ e) = a ^ d ^ a ^ e ^ b ^ d ^ b ^ e ^ c ^ d ^ c ^ e
= (a ^ a ^ b ^ b ^ c ^ c ^ d ^ d ^ d ^ e ^ e ^ e)
= (d ^ e)
AC代码:
class Solution {
public:
int xorAllNums(vector<int>& nums1, vector<int>& nums2) {
int res = 0;
if (nums1.size() & 1)
for (int i = 0; i < nums2.size(); i ++)
res ^= nums2[i];
if (nums2.size() & 1)
for (int i = 0; i < nums1.size(); i ++)
res ^= nums1[i];
return res;
}
};
D. 2426. 满足不等式的数对数目
题目描述:
给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,两个数组的大小都为 n ,同时给你一个整数 diff ,统计满足以下条件的 数对 (i, j) :0 <= i < j <= n - 1 且
nums1[i] - nums1[j] <= nums2[i] - nums2[j] + diff.
请你返回满足条件的 数对数目 。
首先可以将原始公式进行化简:
nums1[i] - nums1[j] <= nums2[i] - nums2[j] + diff.
->
nums1[i] - nums2[i] <= nums1[j] - nums2[j] + diff.
设nums[i] = nums1[i] - nums2[i]
则原始公式变为
nums[i] <= nums[j] + diff
那么这个问题就转换为了经典的逆序对问题了,常用的处理方法有:
- 归并排序
- 离散化 + 树状数组。
可以参考官方题解数组中的逆序对
下边的代码使用的是离散化 + 树状数组的方法。
AC代码:
typedef long long LL;
class Solution {
vector<int> c;
int tr[200010];
int n;
void add(int i, int x) {
for (; i <= n; i += i & (-i)) tr[i] += x;
}
LL sum(int i) {
int ans = 0;
for (; i; i -= i & (-i)) ans += tr[i];
return ans;
}
int get(int x) {
return lower_bound(c.begin(), c.end(), x) - c.begin() + 1;
}
public:
long long numberOfPairs(vector<int>& nums1, vector<int>& nums2, int diff) {
int len = nums1.size();
for (int i = 0; i < len; i ++)
{
nums1[i] -= nums2[i];
c.push_back(nums1[i]);
c.push_back(nums1[i] + diff);
}
sort(c.begin(), c.end());
c.erase(unique(c.begin(), c.end()), c.end());
n = c.size();
LL res = 0;
for (int i = 0; i < len; i ++)
{
res += sum(get(nums1[i] + diff));
add(get(nums1[i]), 1);
}
return res;
}
};