# Leetcode 第267场周赛题解
# Problem A - 买票需要的时间 (opens new window)
# 方法一:模拟
按题意进行模拟。
- 时间复杂度。其中为第个人需要购票的数量。
- 空间复杂度。
参考代码(C++)
class Solution {
public:
int timeRequiredToBuy(vector<int>& tickets, int k) {
queue<int> q;
int n = tickets.size();
for (int i = 0; i < n; ++i)
q.emplace(i);
int t = 0;
while (tickets[k]) {
int u = q.front();
q.pop();
tickets[u]--;
t++;
if (tickets[u])
q.emplace(u);
}
return t;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 方法二:一次遍历
实际上,我们只需要一次遍历就可以解决本题。对于第个及之前的人来说,在第个人刚好买完时,他们的购票数量为;而之后的人,购票数量为。求和即可得到答案。
- 时间复杂度。
- 空间复杂度。
参考代码(Python 3)
class Solution:
def timeRequiredToBuy(self, tickets: List[int], k: int) -> int:
return sum(min(t, tickets[k]) if i <= k else min(t, tickets[k] - 1) for i, t in enumerate(tickets))
1
2
3
2
3
# Problem B - 反转偶数长度组的节点 (opens new window)
# 方法一:模拟
我们可以将链表转换成数组后按要求进行反转,最后再更新链表中的数值即可。
- 时间复杂度。
- 空间复杂度。
参考代码(C++)
class Solution {
public:
ListNode* reverseEvenLengthGroups(ListNode* head) {
vector<int> v;
ListNode *p = head;
while (p != nullptr) {
v.emplace_back(p->val);
p = p->next;
}
int n = v.size();
int i = 0, g = 1;
while (i < n) {
if (g > n - i)
g = n - i;
if (g % 2 == 0)
reverse(v.begin() + i, v.begin() + i + g);
i += g;
g++;
}
p = head;
for (int vi : v) {
p->val = vi;
p = p->next;
}
return head;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Problem C - 解码斜向换位密码 (opens new window)
# 方法一:模拟
理清题意后可知,我们由加密后字符串的长度和行数就可以求得矩阵的列数,然后沿着对角线方向依次取出字符即可。
因为题目说明了答案唯一且结尾不为空格,我们将上面操作得到的字符串末尾的空格全部去除即可得到答案。
- 时间复杂度。
- 空间复杂度。
参考代码(C++)
class Solution {
public:
string decodeCiphertext(string encodedText, int rows) {
int n = encodedText.size();
int cols = n / rows;
string ans;
for (int i = 0; i < cols; ++i) {
for (int j = 0; j < rows; ++j) {
if (i + j >= cols)
break;
int idx = j * cols + i + j;
ans.push_back(encodedText[idx]);
}
}
while (!ans.empty() && ans.back() == ' ')
ans.pop_back();
return ans;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Problem D - 处理含限制条件的好友请求 (opens new window)
# 方法一:并查集
容易想到用并查集来维护好友关系。问题是如何处理限制条件。
假设当前好友请求为,对于这样一条限制条件来说,连接而导致相连,有两种情况:
- 已经相连,已经相连
- 已经相连,已经相连
如果这两种情况都得到排除,则这一条限制条件就不会被违反。
- 时间复杂度。其中为查询数,为限制数,为用户数,为Ackerman函数的反函数,在本题的数据范围内可近似认为常数。
- 空间复杂度。
参考代码(C++)
class UnionFind {
int n;
vector<int> parent, size;
public:
UnionFind(int n) {
this->n = n;
parent = vector<int>(n);
size = vector<int>(n, 1);
for (int i = 0; i < n; ++i)
parent[i] = i;
}
int find(int idx) {
if (parent[idx] == idx)
return idx;
return parent[idx] = find(parent[idx]);
}
void connect(int a, int b) {
int fa = find(a), fb = find(b);
if (fa != fb) {
if (size[fa] > size[fb]) {
parent[fb] = fa;
size[fa] += size[fb];
} else {
parent[fa] = fb;
size[fb] += size[fa];
}
}
}
};
class Solution {
public:
vector<bool> friendRequests(int n, vector<vector<int>>& restrictions, vector<vector<int>>& requests) {
vector<bool> ans;
UnionFind uf(n);
for (auto &req : requests) {
int u = req[0], v = req[1];
if (uf.find(u) == uf.find(v))
ans.push_back(true);
else {
bool valid = true;
for (auto &res : restrictions) {
int p = res[0], q = res[1];
if ((uf.find(u) == uf.find(p) && uf.find(v) == uf.find(q))
|| (uf.find(u) == uf.find(q) && uf.find(v) == uf.find(p))) {
valid = false;
break;
}
}
if (valid) {
uf.connect(u, v);
ans.push_back(true);
} else
ans.push_back(false);
}
}
return ans;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65