本周周赛难度不高,第三题温习一下 Dijstra, 第四题是一道比较奇葩的推理和构造题目。
1.
class Solution:
def isWinner(self, player1: List[int], player2: List[int]) -> int:
n = len(player1)
s1 = s2 = 0
for i in range(n):
s1 += player1[i] * (2 if i > 0 and player1[i - 1] == 10 or i > 1 and player1[i - 2] == 10 else 1)
s2 += player2[i] * (2 if i > 0 and player2[i - 1] == 10 or i > 1 and player2[i - 2] == 10 else 1)
return 1 if s1 > s2 else 2 if s2 > s1 else 0
2.
class Solution {
public:
int firstCompleteIndex(vector<int>& arr, vector<vector<int>>& mat) {
int m = mat.size(), n = mat[0].size(), s = arr.size();
vector<int> row(s + 1), col(s + 1), cr(m), cc(n);
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
row[mat[i][j]] = i;
col[mat[i][j]] = j;
}
}
for(int i = 0; i < s; i++) {
int r = row[arr[i]], c = col[arr[i]];
if(++cr[r] == n or ++cc[c] == m) {
return i;
}
}
return -1;
}
};
3.
不难想到,本题可以使用最短路算法求解。题目中一同提及了 start, target, 以及每条特殊路径的起止,这些节点。然后节点之间的距离就是两者之间的 L1 距离或者特殊路径长度。本题数据规模节点数量只有 400, 即使两两之间连接给出 N^2
条边也是可以求解的。
但是稍加推理不难发现,只有有限的几类边是有意义的,
- start 到 target,只有一条
- start 到特殊路径起点,N 条
- 特殊路径,共有 N 条
- 特殊路径终点到另一条路径起点,共 N^2 条
- 特殊路径终点到 target, N 条
void dijstra(vector<vector<pair<int, int>>>& g, vector<int>& dist, int start) {
typedef pair<int, int> p;
priority_queue<p, vector<p>, greater<p>> q;
q.push({0, start});
while(q.size()) {
auto curr = q.top();
q.pop();
int d = curr.first, x = curr.second;
if(dist[x] <= d) continue;
dist[x] = d;
for(auto child: g[curr.second]) {
int dc = child.first, xc = child.second;
if(dist[xc] > dc + d) {
q.push({dc + d, xc});
}
}
}
}
class Solution {
public:
int minimumCost(vector<int>& start, vector<int>& target, vector<vector<int>>& roads) {
int n = 2 + roads.size() * 2;
vector<vector<pair<int, int>>> g(n);
g[0].push_back({cost(start[0], start[1], target[0], target[1]), n - 1});
int m = roads.size();
for(int i = 0; i < m; i++) {
auto& r = roads[i];
g[0].push_back({cost(start[0], start[1], r[0], r[1]), i * 2 + 1});
g[i * 2 + 1].push_back({r[4], i * 2 + 2});
g[i * 2 + 2].push_back({cost(r[2], r[3], target[0], target[1]), n - 1});
for(int j = 0; j < m; j++) {
if(i == j) continue;
auto& rr = roads[j];
g[i * 2 + 2].push_back({cost(r[2], r[3], rr[0], rr[1]), j * 2 + 1});
}
}
vector<int> dist(n, INT_MAX);
dijstra(g, dist, 0);
return dist[n - 1];
}
int cost(int x1, int y1, int x2, int y2) {
return abs(x1 - x2) + abs(y1 - y2);
}
};
4.
本题其实不难,但比较容易疏漏出错。
不难发现以下几点,
- Beautiful String 的子串也是 Beautiful String
- 只需要保证没有长度为 2 或者 3 的回文子串,就能保证没有任何回文子串
- 没有约束时,字典序最小的 Beautiful String 是 abcabcabc…
因此,一个比较自然的思路是,从字符串末尾开始找,找到第一个能变动的字母,将其改成一个更大的字母,然后后续重复类似于 abcabcabc 的序列。
最终的解法如下。基本思路是,从后向前遍历,每个字母在不构成子串的前提下尝试替换为一个较大的字母,一旦替换成功,就在后续附加 abc 三个字母构成的某个周期序列,并注意不要引入新的回文串。
class Solution {
public:
string smallestBeautifulString(string s, int k) {
int n = s.size();
for(int i = n - 1; i >= 0; i--) {
char b1 = i > 0 ? s[i - 1] : 0, b2 = i > 1 ? s[i - 2] : 0;
int t = s[i] + 1;
while(t == b1 or t == b2) t++;
if(t - 'a' < k) {
s[i] = t;
string seq = "abc";
if(b1 == 'a' and t == 'b') seq = "cab";
if(b1 == 'a' and t == 'c') seq = "bac";
if(b1 == 'b' and t == 'a') seq = "cba";
if(b1 == 'b' and t == 'c') seq = "abc";
if(b1 == 'c' and t == 'a') seq = "bca";
if(b1 == 'c' and t == 'b') seq = "acb";
if(t == 'a') seq = "bca";
if(t == 'b') seq = "acb";
if(b1 == 'a') seq = "bac";
for(int j = i + 1; j < n; j++) {
s[j] = seq[(j - i - 1) % 3];
}
return s;
}
}
return "";
}
};