单周赛 246 题解
本次周赛不难,随便水水就做完了,心情舒适
涉及知识点:小学数学,模拟,深度优先搜索,并差集,桶排序,高性能算法
字符串中的最大奇数
给定一个表示正整数的字符串 \(s\),输出字符串中的最大奇数子字符串,如果不存在奇数,返回空字符串
题解
奇数的个位一定是奇数,所以从后往前遍历字符串 \(s\),找到第一个奇数的位置即可,如果找不到,就意味着不存在奇数
class Solution {
public:
string largestOddNumber(string num) {
int pos = -1;
for (int i = num.length() - 1; i >= 0; --i) {
if ((num[i] - '0') % 2) {pos = i; break;}
}
if (pos == -1) return "";
else return num.substr(0, pos + 1);
}
};
你完成的完整对局数
一个小时中,有四个时间点会开始一场 \(15\) 分钟的完整对局,分别是 HH:00, HH:15, HH:30, HH:45
现在给定两个 HH:MM
格式的时间,分别表示开始时间和终止时间,计算完成的完整对局数
注意,如果终止时间的 HH
小于开始时间的 HH
,说明玩了通宵,也就是说,玩到了第二天
题解
直接 if
特判多种情况
class Solution {
public:
int t1(int x) {return x % 15 ? (x / 15 + 1) * 15 : x;}
int t2(int x) {return x / 15 * 15;}
int numberOfRounds(string st, string ft) {
int h1 = (st[0] - '0') * 10 + st[1] - '0';
int h2 = (ft[0] - '0') * 10 + ft[1] - '0';
int m1 = (st[3] - '0') * 10 + st[4] - '0';
int m2 = (ft[3] - '0') * 10 + ft[4] - '0';
if (h2 < h1 || h2 == h1 && m2 < m1) h2 += 24;
int ans = 0;
if (h1 == h2) {
ans += (4 + (t2(m2) - t1(m1) / 15)) % 4;
}
else if (m1 && m2) {
ans += max(0, h2 - (h1 + 1)) * 4 + (60 - t1(m1)) / 15 + t2(m2) / 15;
}
else if (m1 && !m2) {
ans += max(0, h2 - (h1 + 1)) * 4 + (60 - t1(m1)) / 15;
}
else if (!m1 && m2) {
ans += max(0, h2 - h1) * 4 + t2(m2) / 15;
}
else {
ans += (h2 - h1) * 4;
}
return ans;
}
};
统计子岛屿
给定长和宽一致的两个 \(01\) 矩阵,分别表示两个地图,正如你所猜想的那样,其中的 \(1\) 表示陆地,\(0\) 表示水域,岛屿就是连着的 \(1\) 组成的区域
对于矩阵 \(2\) 中的岛屿,如果他是矩阵 \(1\) 中岛屿的子区域,那么我们称之为子岛屿,现在要统计子岛屿的数量
题解
如果你做过统计岛屿,那就好办了
统计岛屿可以使用 dfs, bfs
等搜索办法来统计数量,也可以使用并查集来统计
这道题只需要在统计的过程中判断一下是否是子岛屿即可,确切的说,只需要检查在特定位置 \(i,\ j\),两个矩阵是否同时为 \(1\) 即可
- 一旦不为 \(1\),那一定不是子岛屿
- 如果为 \(1\),还要继续判断
具体的实现,我是通过在 dfs
的过程中维护一个引用的 \(flag\) 变量来判断的,不排除有其他方法
const int DX[] = {0, 1, 0, -1};
const int DY[] = {1, 0, -1, 0};
class Solution {
public:
bool check(int x, int y, int m, int n)
{
return x >= 0 && x < m && y >= 0 && y < n;
}
void dfs(int x, int y, vector<vector<int>>& vis, vector<vector<int>>& grid1, vector<vector<int>>& grid2, int& flag) {
int m = grid2.size();
int n = grid2[0].size();
vis[x][y] = 1;
if (grid1[x][y] != 1) flag = 0;
for (int i = 0; i < 4; ++i) {
int tx = x + DX[i], ty = y + DY[i];
if (check(tx, ty, m, n) && !vis[tx][ty] && grid2[tx][ty] == 1) {
if (grid1[tx][ty] != 1) {
flag = 0;
}
dfs(tx, ty, vis, grid1, grid2, flag);
}
}
}
int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {
int m = grid2.size();
int n = grid2[0].size();
vector<vector<int>> vis(m, vector<int>(n));
int ans = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (!vis[i][j] && grid2[i][j] == 1) {
int flag = 1;
dfs(i, j, vis, grid1, grid2, flag);
if (flag) {
//cout << i << ' ' << j << endl;
ans++;
}
}
}
}
return ans;
}
};
查询差绝对值的最小值
对于一个数组,我们定义差绝对值的最小值为 数组中两个元素做差的绝对值的最小值
例如 [5,2,3,7,2]
的差绝对值最小值为 |3 - 2| = 1
如果元素一样,例如 [2,2,2]
,那么差绝对值为 -1
是的,我们不考虑相同值的元素做差的情况,也就是说,差绝对值最小值一定不可能是 0
现在给定长为 \(n\) 的数组 \(nums\),以及 \(q\) 个询问,每次询问 \(nums\) 的一个子数组,请计算子数组的差绝对值最小值
数据规定
\(2\leq n\leq 10^5\)
\(1\leq nums[i]\leq 100\)
\(1\leq q\leq 2\cdot 10^4\)
题解
为了计算数组的差绝对值最小值,我们无可避免的需要遍历所有元素
为了一次遍历,还需要维护数组有序,这样才能保证相邻元素做差可能出现最小值,但是这样需要 \(O(nlogn + n)\) 的时间来计算,代价太高
注意到 \(nums[i]\leq 100\),考虑用桶来优化,用桶的好处在于,桶排序的思想自动维护了数组有序,并且遍历的代价也不高,为 \(O(100)\)
具体来说,预处理 \(1\sim 100\) 内各个数字在每个位置 \(i\) 出现次数的前缀和,这样我们在查询 \([L,\ R]\) 区间时,就可以通过差分快速判断某个数字是否出现过
查询的时候,把所有出现过的数字放入临时数组,遍历计算相邻数字的差来维护差绝对值的最小值,特别的,如果最大值等于最小值,返回 \(-1\)
时间复杂度 \(O(100\cdot (n+ q))\)
class Solution {
public:
vector<int> minDifference(vector<int>& n, vector<vector<int>>& q) {
vector<vector<int>> b(n.size() + 1, vector<int>(101));
for (int i = 1; i <= n.size(); ++i) {
b[i][n[i - 1]]++;
for (int j = 1; j <= 100; ++j) {
b[i][j] += b[i - 1][j];
}
}
vector<int> ans;
for (auto &i: q) {
int L = i[0] + 1, R = i[1] + 1;
vector<pair<int, int>> B;
for (int j = 1; j <= 100; ++j) {
int cnt = b[R][j] - b[L - 1][j]; // j 出现的次数
if (cnt > 0) B.push_back(pair<int, int> {j, cnt});
}
int pos = 0, temp = 101;
for (int j = 0; j < B.size() - 1; ++j) {
pair<int, int> x = B[j], y = B[j + 1];
temp = min(temp, y.first - x.first);
}
if (B[0].first == B[B.size() - 1].first) temp = -1;
ans.push_back(temp);
}
return ans;
}
};