这次的题,怎么说呢,就写起来很难受。尤其第三题,题意很模糊,只能靠猜。
当然,大佬们还是很快,我还是太菜了。
周赛传送门
5926. 买票需要的时间
方法一
思路:模拟
时间复杂度:
直观的思路是:使用一个队列模拟买票的整个过程,直到第 个人买票完成。
class Solution {
public:
int timeRequiredToBuy(vector<int>& tickets, int k) {
// 记录答案
int anw = 0;
// 用队列模拟买票过程
queue<int> q;
// 初始化队列
for (auto t : tickets) {
q.push(t);
}
while (q.size() > 0) {
// 排在队首的人买一张票
q.front()--;
// 花费一秒时间
anw ++;
if (q.front() != 0) {
// 如果队首的人未买完,则排到队尾
q.push(q.front());
q.pop();
} else {
// 如果队首的人买完了,则离队。
q.pop();
// 如果是第 k 个人,则退出循环。
if (k == 0) {
break;
}
}
// 更新第 k 个人在队列中的位置。
if (k == 0) {
k = q.size()-1;
} else {
k--;
}
}
return anw;
}
};
方法二
思路:找规律
时间复杂度:
考虑第 人买完票时:
- 对于 ,必然都买了 张票。
- 对于 ,必然都买了 张票。
因此,两部分的累加和即为答案。仅需遍历一次 即可求得。
class Solution {
public:
int timeRequiredToBuy(vector<int>& tickets, int k) {
int sum = 0;
for (int i = 0; i <= k; i++) {
sum += min(tickets[i], tickets[k]);
}
for (int i = k+1; i < tickets.size(); i++) {
sum += min(tickets[i], tickets[k]-1);
}
return sum;
}
};
5927. 反转偶数长度组的节点
思路:偷懒了,借助数组实现了
时间复杂度:
竞赛嘛,怎么快怎么搞了。借助数组实现翻转更易实现,只是需要额外的 的存储空间。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseEvenLengthGroups(ListNode* head) {
// 将节点都放入数组中
vector<ListNode*> vec;
for (auto h = head; h != nullptr; h = h->next) {
vec.push_back(h);
}
for (int i = 1, l = 0, r = 1; l < vec.size(); i++) {
if ((r-l)%2 == 0) {
// 数组的翻转就很简单啦,
reverse(vec.begin()+l, vec.begin()+r);
}
l = r;
r = min(int(vec.size()), l+i+1);
}
// 按序修改 next 指针即可。
for (int i = 0; i+1 < vec.size(); i++) {
//cout << i << ", " << vec[i]->val << endl;
vec[i]->next = vec[i+1];
}
vec.back()->next = nullptr;
return head;
}
};
5928. 解码斜向换位密码
思路:模拟
时间复杂度:
模拟解码的过程即可,详见注释。
class Solution {
public:
string decodeCiphertext(string encodedText, int rows) {
// 首先计算出辅助矩阵的行和列
int r = rows;
int c = encodedText.size()/r;
// 定义anw用于存储答案
string anw;
// 按照题意,只有斜向位置处的字符有意义。
// 又根据题意得知,斜向位置(i,j) 在 encodedText 中的位置为 (c*j + j+i)。
// 因此按序将这些斜向位置处的字符 encodedText[c*j+j+i] 追加至 anw 即可。
for (int i = 0; i < c; i++) {
for (int j = 0; j < r && j+i < c; j++) {
anw += encodedText[c*j + j+i];
}
}
// 最后有个特殊处理,需将尾部的空格全部删除。
// 不过我在题目上并未读出此要求,比赛时纯属蒙对了。
while(anw.back() == ' ') {
anw.pop_back();
}
return anw;
}
};
5929. 处理含限制条件的好友请求
思路:并查集
时间复杂度:, 为请求数量, 为限制数量
并查集模板题啦。每次合并之前,先检查是否会违反限制即可。详见注释。
class Solution {
public:
// 存储并查集的数组
int fa[1000];
// 并查集的 find 函数(带有路径压缩)
int find (int r) {
int x = r;
while (x != fa[x]) {
x = fa[x];
}
while (r != fa[r]) {
int t = fa[r];
fa[r] = x;
r = t;
}
return x;
}
vector<bool> friendRequests(int n, vector<vector<int>>& restrictions, vector<vector<int>>& requests) {
// 初始化并查集
for (int i = 0; i < n; i++) {
fa[i] = i;
}
// anw 用于存储答案
vector<bool> anw;
// 按序处理所有请求
for (const auto req : requests) {
int u = req[0];
int v = req[1];
// 分别查找 u 和 v 所在的集合
int fu = find(u), fv = find(v);
if (fu == fv) {
// 根据并查集的定义,如果 fu == fv,则 u 和 v 已处于相同集合,无需处理了。
anw.push_back(true);
} else {
// 检查所有的 res,判断合并 fu 和 fv 后,是否会违反限制
bool flag = true;
for (const auto &res : restrictions) {
int ru = res[0], rv = res[1];
int fru = find(ru), frv = find(rv);
// ru 和 rv 恰好分属 fu 和 fv 两个集合,则显然不能合并啦🙅♀️
if ((fru == fu && frv == fv) || (fru == fv && frv == fu)) {
flag = false;
break;
}
}
anw.push_back(flag);
if (flag) {
// 能合则合
fa[fu] = fv;
}
}
}
return anw;
}
};